blob: 894d1c5d994bbed16d25668757469b6d430fda54 [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
10import atexit
Larry Hastings31826802013-10-19 00:09:25 -070011import collections
12import contextlib
Larry Hastings7726ac92014-01-31 22:03:12 -080013import copy
14import cpp
Larry Hastings31826802013-10-19 00:09:25 -070015import functools
16import hashlib
17import inspect
18import io
19import itertools
20import os
Larry Hastingsbebf7352014-01-17 17:47:17 -080021import pprint
Larry Hastings31826802013-10-19 00:09:25 -070022import re
23import shlex
Larry Hastings581ee362014-01-28 05:00:08 -080024import string
Larry Hastings31826802013-10-19 00:09:25 -070025import sys
26import tempfile
27import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010028import traceback
Larry Hastingsdbfdc382015-05-04 06:59:46 -070029import types
Larry Hastingsbebf7352014-01-17 17:47:17 -080030import uuid
Larry Hastings31826802013-10-19 00:09:25 -070031
Larry Hastingsdbfdc382015-05-04 06:59:46 -070032from types import *
33NoneType = type(None)
34
Larry Hastings31826802013-10-19 00:09:25 -070035# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070036#
37# soon:
38#
39# * allow mixing any two of {positional-only, positional-or-keyword,
40# keyword-only}
41# * dict constructor uses positional-only and keyword-only
42# * max and min use positional only with an optional group
43# and keyword-only
44#
Larry Hastings31826802013-10-19 00:09:25 -070045
Larry Hastingsebdcb502013-11-23 14:54:00 -080046version = '1'
47
Larry Hastings31826802013-10-19 00:09:25 -070048_empty = inspect._empty
49_void = inspect._void
50
Larry Hastings4a55fc52014-01-12 11:09:57 -080051NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070052
53class Unspecified:
54 def __repr__(self):
55 return '<Unspecified>'
56
57unspecified = Unspecified()
58
59
60class Null:
61 def __repr__(self):
62 return '<Null>'
63
64NULL = Null()
65
66
Larry Hastings2a727912014-01-16 11:32:01 -080067class Unknown:
68 def __repr__(self):
69 return '<Unknown>'
70
71unknown = Unknown()
72
Zachary Ware8ef887c2015-04-13 18:22:35 -050073sig_end_marker = '--'
74
Larry Hastings2a727912014-01-16 11:32:01 -080075
Larry Hastings0759f842015-04-03 13:09:02 -070076_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output")
77
Larry Hastings31826802013-10-19 00:09:25 -070078def _text_accumulator():
79 text = []
80 def output():
81 s = ''.join(text)
82 text.clear()
83 return s
Larry Hastings0759f842015-04-03 13:09:02 -070084 return _text_accumulator_nt(text, text.append, output)
Larry Hastings31826802013-10-19 00:09:25 -070085
86
Larry Hastings0759f842015-04-03 13:09:02 -070087text_accumulator_nt = collections.namedtuple("text_accumulator", "text append")
88
Larry Hastings31826802013-10-19 00:09:25 -070089def text_accumulator():
90 """
91 Creates a simple text accumulator / joiner.
92
93 Returns a pair of callables:
94 append, output
95 "append" appends a string to the accumulator.
96 "output" returns the contents of the accumulator
97 joined together (''.join(accumulator)) and
98 empties the accumulator.
99 """
100 text, append, output = _text_accumulator()
Larry Hastings0759f842015-04-03 13:09:02 -0700101 return text_accumulator_nt(append, output)
Larry Hastings31826802013-10-19 00:09:25 -0700102
103
Larry Hastingsbebf7352014-01-17 17:47:17 -0800104def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -0700105 joined = " ".join([str(a) for a in args])
106 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800107 if fail:
108 add("Error")
109 else:
110 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -0700111 if clinic:
112 if filename is None:
113 filename = clinic.filename
Larry Hastings581ee362014-01-28 05:00:08 -0800114 if getattr(clinic, 'block_parser', None) and (line_number is None):
Larry Hastings31826802013-10-19 00:09:25 -0700115 line_number = clinic.block_parser.line_number
116 if filename is not None:
117 add(' in file "' + filename + '"')
118 if line_number is not None:
119 add(" on line " + str(line_number))
120 add(':\n')
121 add(joined)
122 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800123 if fail:
124 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700125
126
Larry Hastingsbebf7352014-01-17 17:47:17 -0800127def warn(*args, filename=None, line_number=None):
128 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
129
130def fail(*args, filename=None, line_number=None):
131 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
132
Larry Hastings31826802013-10-19 00:09:25 -0700133
134def quoted_for_c_string(s):
135 for old, new in (
Zachary Ware9d7849f2014-01-25 03:26:20 -0600136 ('\\', '\\\\'), # must be first!
Larry Hastings31826802013-10-19 00:09:25 -0700137 ('"', '\\"'),
138 ("'", "\\'"),
139 ):
140 s = s.replace(old, new)
141 return s
142
Larry Hastings4903e002014-01-18 00:26:16 -0800143def c_repr(s):
144 return '"' + s + '"'
145
146
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700147is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
148
149def is_legal_py_identifier(s):
150 return all(is_legal_c_identifier(field) for field in s.split('.'))
151
Larry Hastingsbebf7352014-01-17 17:47:17 -0800152# identifiers that are okay in Python but aren't a good idea in C.
153# so if they're used Argument Clinic will add "_value" to the end
154# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700155c_keywords = set("""
Larry Hastings5c661892014-01-24 06:17:25 -0800156asm auto break case char const continue default do double
157else enum extern float for goto if inline int long
158register return short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800159typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700160""".strip().split())
161
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700162def ensure_legal_c_identifier(s):
163 # for now, just complain if what we're given isn't legal
164 if not is_legal_c_identifier(s):
165 fail("Illegal C identifier: {}".format(s))
166 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700167 if s in c_keywords:
168 return s + "_value"
169 return s
170
171def rstrip_lines(s):
172 text, add, output = _text_accumulator()
173 for line in s.split('\n'):
174 add(line.rstrip())
175 add('\n')
176 text.pop()
177 return output()
178
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +0300179def format_escape(s):
180 # double up curly-braces, this string will be used
181 # as part of a format_map() template later
182 s = s.replace('{', '{{')
183 s = s.replace('}', '}}')
184 return s
185
Larry Hastings31826802013-10-19 00:09:25 -0700186def linear_format(s, **kwargs):
187 """
188 Perform str.format-like substitution, except:
189 * The strings substituted must be on lines by
190 themselves. (This line is the "source line".)
191 * If the substitution text is empty, the source line
192 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800193 * If the field is not recognized, the original line
194 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700195 * If the substitution text is not empty:
196 * Each line of the substituted text is indented
197 by the indent of the source line.
198 * A newline will be added to the end.
199 """
200
201 add, output = text_accumulator()
202 for line in s.split('\n'):
203 indent, curly, trailing = line.partition('{')
204 if not curly:
205 add(line)
206 add('\n')
207 continue
208
Martin Panter4177e7c2016-02-14 03:23:13 +0000209 name, curly, trailing = trailing.partition('}')
Larry Hastings31826802013-10-19 00:09:25 -0700210 if not curly or name not in kwargs:
211 add(line)
212 add('\n')
213 continue
214
215 if trailing:
216 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
217 if indent.strip():
218 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
219
220 value = kwargs[name]
221 if not value:
222 continue
223
224 value = textwrap.indent(rstrip_lines(value), indent)
225 add(value)
226 add('\n')
227
228 return output()[:-1]
229
Larry Hastingsbebf7352014-01-17 17:47:17 -0800230def indent_all_lines(s, prefix):
231 """
232 Returns 's', with 'prefix' prepended to all lines.
233
234 If the last line is empty, prefix is not prepended
235 to it. (If s is blank, returns s unchanged.)
236
237 (textwrap.indent only adds to non-blank lines.)
238 """
239 split = s.split('\n')
240 last = split.pop()
241 final = []
242 for line in split:
243 final.append(prefix)
244 final.append(line)
245 final.append('\n')
246 if last:
247 final.append(prefix)
248 final.append(last)
249 return ''.join(final)
250
251def suffix_all_lines(s, suffix):
252 """
253 Returns 's', with 'suffix' appended to all lines.
254
255 If the last line is empty, suffix is not appended
256 to it. (If s is blank, returns s unchanged.)
257 """
258 split = s.split('\n')
259 last = split.pop()
260 final = []
261 for line in split:
262 final.append(line)
263 final.append(suffix)
264 final.append('\n')
265 if last:
266 final.append(last)
267 final.append(suffix)
268 return ''.join(final)
269
270
Larry Hastingsebdcb502013-11-23 14:54:00 -0800271def version_splitter(s):
272 """Splits a version string into a tuple of integers.
273
274 The following ASCII characters are allowed, and employ
275 the following conversions:
276 a -> -3
277 b -> -2
278 c -> -1
279 (This permits Python-style version strings such as "1.4b3".)
280 """
281 version = []
282 accumulator = []
283 def flush():
284 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800285 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800286 version.append(int(''.join(accumulator)))
287 accumulator.clear()
288
289 for c in s:
290 if c.isdigit():
291 accumulator.append(c)
292 elif c == '.':
293 flush()
294 elif c in 'abc':
295 flush()
296 version.append('abc'.index(c) - 3)
297 else:
298 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
299 flush()
300 return tuple(version)
301
302def version_comparitor(version1, version2):
303 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
304 for i, (a, b) in enumerate(iterator):
305 if a < b:
306 return -1
307 if a > b:
308 return 1
309 return 0
310
Larry Hastings31826802013-10-19 00:09:25 -0700311
312class CRenderData:
313 def __init__(self):
314
315 # The C statements to declare variables.
316 # Should be full lines with \n eol characters.
317 self.declarations = []
318
319 # The C statements required to initialize the variables before the parse call.
320 # Should be full lines with \n eol characters.
321 self.initializers = []
322
Larry Hastingsc2047262014-01-25 20:43:29 -0800323 # The C statements needed to dynamically modify the values
324 # parsed by the parse call, before calling the impl.
325 self.modifications = []
326
Larry Hastings31826802013-10-19 00:09:25 -0700327 # The entries for the "keywords" array for PyArg_ParseTuple.
328 # Should be individual strings representing the names.
329 self.keywords = []
330
331 # The "format units" for PyArg_ParseTuple.
332 # Should be individual strings that will get
333 self.format_units = []
334
335 # The varargs arguments for PyArg_ParseTuple.
336 self.parse_arguments = []
337
338 # The parameter declarations for the impl function.
339 self.impl_parameters = []
340
341 # The arguments to the impl function at the time it's called.
342 self.impl_arguments = []
343
344 # For return converters: the name of the variable that
345 # should receive the value returned by the impl.
346 self.return_value = "return_value"
347
348 # For return converters: the code to convert the return
349 # value from the parse function. This is also where
350 # you should check the _return_value for errors, and
351 # "goto exit" if there are any.
352 self.return_conversion = []
353
354 # The C statements required to clean up after the impl call.
355 self.cleanup = []
356
357
Larry Hastings581ee362014-01-28 05:00:08 -0800358class FormatCounterFormatter(string.Formatter):
359 """
360 This counts how many instances of each formatter
361 "replacement string" appear in the format string.
362
363 e.g. after evaluating "string {a}, {b}, {c}, {a}"
364 the counts dict would now look like
365 {'a': 2, 'b': 1, 'c': 1}
366 """
367 def __init__(self):
368 self.counts = collections.Counter()
369
370 def get_value(self, key, args, kwargs):
371 self.counts[key] += 1
372 return ''
373
Larry Hastings31826802013-10-19 00:09:25 -0700374class Language(metaclass=abc.ABCMeta):
375
376 start_line = ""
377 body_prefix = ""
378 stop_line = ""
379 checksum_line = ""
380
Larry Hastings7726ac92014-01-31 22:03:12 -0800381 def __init__(self, filename):
382 pass
383
Larry Hastings31826802013-10-19 00:09:25 -0700384 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800385 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700386 pass
387
Larry Hastings7726ac92014-01-31 22:03:12 -0800388 def parse_line(self, line):
389 pass
390
Larry Hastings31826802013-10-19 00:09:25 -0700391 def validate(self):
Larry Hastings581ee362014-01-28 05:00:08 -0800392 def assert_only_one(attr, *additional_fields):
393 """
394 Ensures that the string found at getattr(self, attr)
395 contains exactly one formatter replacement string for
396 each valid field. The list of valid fields is
397 ['dsl_name'] extended by additional_fields.
398
399 e.g.
400 self.fmt = "{dsl_name} {a} {b}"
401
402 # this passes
403 self.assert_only_one('fmt', 'a', 'b')
404
405 # this fails, the format string has a {b} in it
406 self.assert_only_one('fmt', 'a')
407
408 # this fails, the format string doesn't have a {c} in it
409 self.assert_only_one('fmt', 'a', 'b', 'c')
410
411 # this fails, the format string has two {a}s in it,
412 # it must contain exactly one
413 self.fmt2 = '{dsl_name} {a} {a}'
414 self.assert_only_one('fmt2', 'a')
415
416 """
417 fields = ['dsl_name']
418 fields.extend(additional_fields)
419 line = getattr(self, attr)
420 fcf = FormatCounterFormatter()
421 fcf.format(line)
422 def local_fail(should_be_there_but_isnt):
423 if should_be_there_but_isnt:
424 fail("{} {} must contain {{{}}} exactly once!".format(
425 self.__class__.__name__, attr, name))
426 else:
427 fail("{} {} must not contain {{{}}}!".format(
428 self.__class__.__name__, attr, name))
429
430 for name, count in fcf.counts.items():
431 if name in fields:
432 if count > 1:
433 local_fail(True)
434 else:
435 local_fail(False)
436 for name in fields:
437 if fcf.counts.get(name) != 1:
438 local_fail(True)
439
Larry Hastings31826802013-10-19 00:09:25 -0700440 assert_only_one('start_line')
441 assert_only_one('stop_line')
Larry Hastings31826802013-10-19 00:09:25 -0700442
Larry Hastings581ee362014-01-28 05:00:08 -0800443 field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
444 assert_only_one('checksum_line', field)
Larry Hastings31826802013-10-19 00:09:25 -0700445
446
447
448class PythonLanguage(Language):
449
450 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800451 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700452 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800453 stop_line = "#[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800454 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700455
456
457def permute_left_option_groups(l):
458 """
459 Given [1, 2, 3], should yield:
460 ()
461 (3,)
462 (2, 3)
463 (1, 2, 3)
464 """
465 yield tuple()
466 accumulator = []
467 for group in reversed(l):
468 accumulator = list(group) + accumulator
469 yield tuple(accumulator)
470
471
472def permute_right_option_groups(l):
473 """
474 Given [1, 2, 3], should yield:
475 ()
476 (1,)
477 (1, 2)
478 (1, 2, 3)
479 """
480 yield tuple()
481 accumulator = []
482 for group in l:
483 accumulator.extend(group)
484 yield tuple(accumulator)
485
486
487def permute_optional_groups(left, required, right):
488 """
489 Generator function that computes the set of acceptable
490 argument lists for the provided iterables of
491 argument groups. (Actually it generates a tuple of tuples.)
492
493 Algorithm: prefer left options over right options.
494
495 If required is empty, left must also be empty.
496 """
497 required = tuple(required)
498 result = []
499
500 if not required:
501 assert not left
502
503 accumulator = []
504 counts = set()
505 for r in permute_right_option_groups(right):
506 for l in permute_left_option_groups(left):
507 t = l + required + r
508 if len(t) in counts:
509 continue
510 counts.add(len(t))
511 accumulator.append(t)
512
513 accumulator.sort(key=len)
514 return tuple(accumulator)
515
516
Larry Hastings7726ac92014-01-31 22:03:12 -0800517def strip_leading_and_trailing_blank_lines(s):
518 lines = s.rstrip().split('\n')
519 while lines:
520 line = lines[0]
521 if line.strip():
522 break
523 del lines[0]
524 return '\n'.join(lines)
525
526@functools.lru_cache()
527def normalize_snippet(s, *, indent=0):
528 """
529 Reformats s:
530 * removes leading and trailing blank lines
531 * ensures that it does not end with a newline
532 * dedents so the first nonwhite character on any line is at column "indent"
533 """
534 s = strip_leading_and_trailing_blank_lines(s)
535 s = textwrap.dedent(s)
536 if indent:
537 s = textwrap.indent(s, ' ' * indent)
538 return s
539
540
Larry Hastings89964c42015-04-14 18:07:59 -0400541def wrap_declarations(text, length=78):
542 """
543 A simple-minded text wrapper for C function declarations.
544
545 It views a declaration line as looking like this:
546 xxxxxxxx(xxxxxxxxx,xxxxxxxxx)
547 If called with length=30, it would wrap that line into
548 xxxxxxxx(xxxxxxxxx,
549 xxxxxxxxx)
550 (If the declaration has zero or one parameters, this
551 function won't wrap it.)
552
553 If this doesn't work properly, it's probably better to
554 start from scratch with a more sophisticated algorithm,
555 rather than try and improve/debug this dumb little function.
556 """
557 lines = []
558 for line in text.split('\n'):
559 prefix, _, after_l_paren = line.partition('(')
560 if not after_l_paren:
561 lines.append(line)
562 continue
563 parameters, _, after_r_paren = after_l_paren.partition(')')
564 if not _:
565 lines.append(line)
566 continue
567 if ',' not in parameters:
568 lines.append(line)
569 continue
570 parameters = [x.strip() + ", " for x in parameters.split(',')]
571 prefix += "("
572 if len(prefix) < length:
573 spaces = " " * len(prefix)
574 else:
575 spaces = " " * 4
576
577 while parameters:
578 line = prefix
579 first = True
580 while parameters:
581 if (not first and
582 (len(line) + len(parameters[0]) > length)):
583 break
584 line += parameters.pop(0)
585 first = False
586 if not parameters:
587 line = line.rstrip(", ") + ")" + after_r_paren
588 lines.append(line.rstrip())
589 prefix = spaces
590 return "\n".join(lines)
591
592
Larry Hastings31826802013-10-19 00:09:25 -0700593class CLanguage(Language):
594
Larry Hastings61272b72014-01-07 12:41:53 -0800595 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700596 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800597 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700598 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800599 stop_line = "[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800600 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700601
Larry Hastings7726ac92014-01-31 22:03:12 -0800602 def __init__(self, filename):
603 super().__init__(filename)
604 self.cpp = cpp.Monitor(filename)
605 self.cpp.fail = fail
606
607 def parse_line(self, line):
608 self.cpp.writeline(line)
609
Larry Hastingsbebf7352014-01-17 17:47:17 -0800610 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700611 function = None
612 for o in signatures:
613 if isinstance(o, Function):
614 if function:
615 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
616 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800617 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700618
619 def docstring_for_c_string(self, f):
620 text, add, output = _text_accumulator()
621 # turn docstring into a properly quoted C string
622 for line in f.docstring.split('\n'):
623 add('"')
624 add(quoted_for_c_string(line))
625 add('\\n"\n')
626
Zachary Ware8ef887c2015-04-13 18:22:35 -0500627 if text[-2] == sig_end_marker:
628 # If we only have a signature, add the blank line that the
629 # __text_signature__ getter expects to be there.
630 add('"\\n"')
631 else:
632 text.pop()
633 add('"')
Larry Hastings31826802013-10-19 00:09:25 -0700634 return ''.join(text)
635
Larry Hastingsbebf7352014-01-17 17:47:17 -0800636 def output_templates(self, f):
637 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800638 assert parameters
639 assert isinstance(parameters[0].converter, self_converter)
640 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800641 converters = [p.converter for p in parameters]
642
643 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
644 default_return_converter = (not f.return_converter or
645 f.return_converter.type == 'PyObject *')
646
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300647 positional = parameters and parameters[-1].is_positional_only()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800648 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
649 first_optional = len(parameters)
650 for i, p in enumerate(parameters):
651 c = p.converter
652 if type(c) != object_converter:
653 break
654 if c.format_unit != 'O':
655 break
656 if p.default is not unspecified:
657 first_optional = min(first_optional, i)
658 else:
659 all_boring_objects = True
660
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800661 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
662
Larry Hastingsbebf7352014-01-17 17:47:17 -0800663 meth_o = (len(parameters) == 1 and
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +0300664 parameters[0].is_positional_only() and
Larry Hastingsbebf7352014-01-17 17:47:17 -0800665 not converters[0].is_optional() and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800666 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800667
Larry Hastings7726ac92014-01-31 22:03:12 -0800668 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800669 #
670 # docstring_prototype
671 # docstring_definition
672 # impl_prototype
673 # methoddef_define
674 # parser_prototype
675 # parser_definition
676 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800677 # cpp_if
678 # cpp_endif
679 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800680
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800681 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700682
Larry Hastings7726ac92014-01-31 22:03:12 -0800683 methoddef_define = normalize_snippet("""
684 #define {methoddef_name} \\
685 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
686 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800687 if new_or_init and not f.docstring:
688 docstring_prototype = docstring_definition = ''
689 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800690 docstring_prototype = normalize_snippet("""
691 PyDoc_VAR({c_basename}__doc__);
692 """)
693 docstring_definition = normalize_snippet("""
694 PyDoc_STRVAR({c_basename}__doc__,
695 {docstring});
696 """)
697 impl_definition = normalize_snippet("""
698 static {impl_return_type}
699 {c_basename}_impl({impl_parameters})
700 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800701 impl_prototype = parser_prototype = parser_definition = None
702
Larry Hastings7726ac92014-01-31 22:03:12 -0800703 parser_prototype_keyword = normalize_snippet("""
704 static PyObject *
705 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
706 """)
707
708 parser_prototype_varargs = normalize_snippet("""
709 static PyObject *
710 {c_basename}({self_type}{self_name}, PyObject *args)
711 """)
712
Victor Stinner0c8c3892017-01-17 01:42:54 +0100713 parser_prototype_fastcall = normalize_snippet("""
714 static PyObject *
715 {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
716 """)
717
Larry Hastings7726ac92014-01-31 22:03:12 -0800718 # parser_body_fields remembers the fields passed in to the
719 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800720 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800721 def parser_body(prototype, *fields):
722 nonlocal parser_body_fields
723 add, output = text_accumulator()
724 add(prototype)
725 parser_body_fields = fields
Larry Hastings7726ac92014-01-31 22:03:12 -0800726
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800727 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800728 fields.insert(0, normalize_snippet("""
729 {{
730 {return_value_declaration}
731 {declarations}
732 {initializers}
733 """) + "\n")
734 # just imagine--your code is here in the middle
735 fields.append(normalize_snippet("""
736 {modifications}
737 {return_value} = {c_basename}_impl({impl_arguments});
738 {return_conversion}
739
740 {exit_label}
741 {cleanup}
742 return return_value;
743 }}
744 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800745 for field in fields:
746 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800747 add(field)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800748 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800749
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800750 def insert_keywords(s):
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300751 return linear_format(s, declarations=
752 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
753 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n'
754 '{declarations}')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800755
756 if not parameters:
757 # no parameters, METH_NOARGS
758
759 flags = "METH_NOARGS"
760
Larry Hastings7726ac92014-01-31 22:03:12 -0800761 parser_prototype = normalize_snippet("""
762 static PyObject *
763 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
764 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800765 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800766
767 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800768 parser_definition = parser_prototype + '\n' + normalize_snippet("""
769 {{
770 return {c_basename}_impl({impl_arguments});
771 }}
772 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800773 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800774 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700775
Larry Hastingsbebf7352014-01-17 17:47:17 -0800776 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800777 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800778
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300779 if (isinstance(converters[0], object_converter) and
780 converters[0].format_unit == 'O'):
781 meth_o_prototype = normalize_snippet("""
782 static PyObject *
783 {c_basename}({impl_parameters})
784 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800785
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300786 if default_return_converter:
787 # maps perfectly to METH_O, doesn't need a return converter.
788 # so we skip making a parse function
789 # and call directly into the impl function.
790 impl_prototype = parser_prototype = parser_definition = ''
791 impl_definition = meth_o_prototype
792 else:
793 # SLIGHT HACK
794 # use impl_parameters for the parser here!
795 parser_prototype = meth_o_prototype
796 parser_definition = parser_body(parser_prototype)
797
Larry Hastingsbebf7352014-01-17 17:47:17 -0800798 else:
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300799 argname = 'arg'
800 if parameters[0].name == argname:
801 argname += '_'
802 parser_prototype = normalize_snippet("""
803 static PyObject *
804 {c_basename}({self_type}{self_name}, PyObject *%s)
805 """ % argname)
806
807 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300808 if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300809 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300810 }}
Serhiy Storchaka92e8af62015-04-04 00:12:11 +0300811 """ % argname, indent=4))
Larry Hastings31826802013-10-19 00:09:25 -0700812
Larry Hastingsbebf7352014-01-17 17:47:17 -0800813 elif has_option_groups:
814 # positional parameters with option groups
815 # (we have to generate lots of PyArg_ParseTuple calls
816 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700817
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800818 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800819 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700820
Larry Hastings7726ac92014-01-31 22:03:12 -0800821 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700822
Larry Hastingsbebf7352014-01-17 17:47:17 -0800823 elif positional and all_boring_objects:
824 # positional-only, but no option groups,
825 # and nothing but normal objects:
826 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700827
Victor Stinner093119e2017-01-17 02:35:41 +0100828 if not new_or_init:
829 flags = "METH_FASTCALL"
830 parser_prototype = parser_prototype_fastcall
Larry Hastings31826802013-10-19 00:09:25 -0700831
Victor Stinner093119e2017-01-17 02:35:41 +0100832 parser_definition = parser_body(parser_prototype, normalize_snippet("""
833 if (!_PyArg_UnpackStack(args, nargs, "{name}",
834 {unpack_min}, {unpack_max},
835 {parse_arguments})) {{
836 goto exit;
837 }}
838
839 if ({self_type_check}!_PyArg_NoStackKeywords("{name}", kwnames)) {{
840 goto exit;
841 }}
842 """, indent=4))
843 else:
844 flags = "METH_VARARGS"
845 parser_prototype = parser_prototype_varargs
846
847 parser_definition = parser_body(parser_prototype, normalize_snippet("""
848 if (!PyArg_UnpackTuple(args, "{name}",
849 {unpack_min}, {unpack_max},
850 {parse_arguments})) {{
851 goto exit;
852 }}
853 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800854
855 elif positional:
Victor Stinner0c8c3892017-01-17 01:42:54 +0100856 if not new_or_init:
857 # positional-only, but no option groups
858 # we only need one call to _PyArg_ParseStack
Larry Hastingsbebf7352014-01-17 17:47:17 -0800859
Victor Stinner0c8c3892017-01-17 01:42:54 +0100860 flags = "METH_FASTCALL"
861 parser_prototype = parser_prototype_fastcall
Larry Hastingsbebf7352014-01-17 17:47:17 -0800862
Victor Stinner0c8c3892017-01-17 01:42:54 +0100863 parser_definition = parser_body(parser_prototype, normalize_snippet("""
864 if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
865 {parse_arguments})) {{
866 goto exit;
867 }}
868
869 if ({self_type_check}!_PyArg_NoStackKeywords("{name}", kwnames)) {{
870 goto exit;
871 }}
872 """, indent=4))
873 else:
874 # positional-only, but no option groups
875 # we only need one call to PyArg_ParseTuple
876
877 flags = "METH_VARARGS"
878 parser_prototype = parser_prototype_varargs
879
880 parser_definition = parser_body(parser_prototype, normalize_snippet("""
881 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
882 {parse_arguments})) {{
883 goto exit;
884 }}
885 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800886
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700887 elif not new_or_init:
888 flags = "METH_FASTCALL"
889
890 parser_prototype = parser_prototype_fastcall
891
892 body = normalize_snippet("""
Victor Stinner3e1fad62017-01-17 01:29:01 +0100893 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700894 {parse_arguments})) {{
895 goto exit;
896 }}
897 """, indent=4)
898 parser_definition = parser_body(parser_prototype, body)
899 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800900 else:
901 # positional-or-keyword arguments
902 flags = "METH_VARARGS|METH_KEYWORDS"
903
Larry Hastings7726ac92014-01-31 22:03:12 -0800904 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800905
Larry Hastings7726ac92014-01-31 22:03:12 -0800906 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300907 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300908 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800909 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300910 }}
911 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300912 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800913 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700914
Larry Hastings31826802013-10-19 00:09:25 -0700915
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800916 if new_or_init:
917 methoddef_define = ''
918
919 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800920 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800921 else:
922 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800923 parser_prototype = normalize_snippet("""
924 static int
925 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
926 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800927
928 fields = list(parser_body_fields)
929 parses_positional = 'METH_NOARGS' not in flags
930 parses_keywords = 'METH_KEYWORDS' in flags
931 if parses_keywords:
932 assert parses_positional
933
934 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800935 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300936 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800937 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300938 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800939 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800940 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800941 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300942 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800943 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300944 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800945 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800946
947 parser_definition = parser_body(parser_prototype, *fields)
948 if parses_keywords:
949 parser_definition = insert_keywords(parser_definition)
950
Larry Hastings31826802013-10-19 00:09:25 -0700951
Larry Hastingsbebf7352014-01-17 17:47:17 -0800952 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800953 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700954
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800955 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700956
Larry Hastings7726ac92014-01-31 22:03:12 -0800957 methoddef_ifndef = ''
958 conditional = self.cpp.condition()
959 if not conditional:
960 cpp_if = cpp_endif = ''
961 else:
962 cpp_if = "#if " + conditional
963 cpp_endif = "#endif /* " + conditional + " */"
964
Larry Hastings0759f842015-04-03 13:09:02 -0700965 if methoddef_define and f.name not in clinic.ifndef_symbols:
966 clinic.ifndef_symbols.add(f.name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800967 methoddef_ifndef = normalize_snippet("""
968 #ifndef {methoddef_name}
969 #define {methoddef_name}
970 #endif /* !defined({methoddef_name}) */
971 """)
972
973
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800974 # add ';' to the end of parser_prototype and impl_prototype
975 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800976 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800977 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800978 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800979 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700980
Larry Hastingsbebf7352014-01-17 17:47:17 -0800981 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800982 impl_prototype = impl_definition
983 if impl_prototype:
984 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700985
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800986 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800987
988 d = {
989 "docstring_prototype" : docstring_prototype,
990 "docstring_definition" : docstring_definition,
991 "impl_prototype" : impl_prototype,
992 "methoddef_define" : methoddef_define,
993 "parser_prototype" : parser_prototype,
994 "parser_definition" : parser_definition,
995 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800996 "cpp_if" : cpp_if,
997 "cpp_endif" : cpp_endif,
998 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800999 }
1000
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001001 # make sure we didn't forget to assign something,
1002 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -08001003 d2 = {}
1004 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001005 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001006 if value:
1007 value = '\n' + value + '\n'
1008 d2[name] = value
1009 return d2
Larry Hastings31826802013-10-19 00:09:25 -07001010
1011 @staticmethod
1012 def group_to_variable_name(group):
1013 adjective = "left_" if group < 0 else "right_"
1014 return "group_" + adjective + str(abs(group))
1015
1016 def render_option_group_parsing(self, f, template_dict):
1017 # positional only, grouped, optional arguments!
1018 # can be optional on the left or right.
1019 # here's an example:
1020 #
1021 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
1022 #
1023 # Here group D are required, and all other groups are optional.
1024 # (Group D's "group" is actually None.)
1025 # We can figure out which sets of arguments we have based on
1026 # how many arguments are in the tuple.
1027 #
1028 # Note that you need to count up on both sides. For example,
1029 # you could have groups C+D, or C+D+E, or C+D+E+F.
1030 #
1031 # What if the number of arguments leads us to an ambiguous result?
1032 # Clinic prefers groups on the left. So in the above example,
1033 # five arguments would map to B+C, not C+D.
1034
1035 add, output = text_accumulator()
1036 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001037 if isinstance(parameters[0].converter, self_converter):
1038 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001039
1040 groups = []
1041 group = None
1042 left = []
1043 right = []
1044 required = []
1045 last = unspecified
1046
1047 for p in parameters:
1048 group_id = p.group
1049 if group_id != last:
1050 last = group_id
1051 group = []
1052 if group_id < 0:
1053 left.append(group)
1054 elif group_id == 0:
1055 group = required
1056 else:
1057 right.append(group)
1058 group.append(p)
1059
1060 count_min = sys.maxsize
1061 count_max = -1
1062
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001063 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001064 for subset in permute_optional_groups(left, required, right):
1065 count = len(subset)
1066 count_min = min(count_min, count)
1067 count_max = max(count_max, count)
1068
Larry Hastings583baa82014-01-12 08:49:30 -08001069 if count == 0:
1070 add(""" case 0:
1071 break;
1072""")
1073 continue
1074
Larry Hastings31826802013-10-19 00:09:25 -07001075 group_ids = {p.group for p in subset} # eliminate duplicates
1076 d = {}
1077 d['count'] = count
1078 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001079 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1080
1081 parse_arguments = []
1082 for p in subset:
1083 p.converter.parse_argument(parse_arguments)
1084 d['parse_arguments'] = ", ".join(parse_arguments)
1085
1086 group_ids.discard(0)
1087 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1088 lines = "\n".join(lines)
1089
1090 s = """
1091 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001092 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001093 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001094 }}
Larry Hastings31826802013-10-19 00:09:25 -07001095 {group_booleans}
1096 break;
1097"""[1:]
1098 s = linear_format(s, group_booleans=lines)
1099 s = s.format_map(d)
1100 add(s)
1101
1102 add(" default:\n")
1103 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1104 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001105 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001106 add("}")
1107 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001108
Larry Hastingsbebf7352014-01-17 17:47:17 -08001109 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001110 if not f:
1111 return ""
1112
1113 add, output = text_accumulator()
1114 data = CRenderData()
1115
Larry Hastings7726ac92014-01-31 22:03:12 -08001116 assert f.parameters, "We should always have a 'self' at this point!"
1117 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001118 converters = [p.converter for p in parameters]
1119
Larry Hastings5c661892014-01-24 06:17:25 -08001120 templates = self.output_templates(f)
1121
1122 f_self = parameters[0]
1123 selfless = parameters[1:]
1124 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1125
1126 last_group = 0
1127 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001128 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001129 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1130 default_return_converter = (not f.return_converter or
1131 f.return_converter.type == 'PyObject *')
1132 has_option_groups = False
1133
1134 # offset i by -1 because first_optional needs to ignore self
1135 for i, p in enumerate(parameters, -1):
1136 c = p.converter
1137
1138 if (i != -1) and (p.default is not unspecified):
1139 first_optional = min(first_optional, i)
1140
1141 # insert group variable
1142 group = p.group
1143 if last_group != group:
1144 last_group = group
1145 if group:
1146 group_name = self.group_to_variable_name(group)
1147 data.impl_arguments.append(group_name)
1148 data.declarations.append("int " + group_name + " = 0;")
1149 data.impl_parameters.append("int " + group_name)
1150 has_option_groups = True
1151
1152 c.render(p, data)
1153
1154 if has_option_groups and (not positional):
1155 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1156
1157 # HACK
1158 # when we're METH_O, but have a custom return converter,
1159 # we use "impl_parameters" for the parsing function
1160 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001161 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001162 # as variables in the parsing function. but since it's
1163 # METH_O, we have exactly one anyway, so we know exactly
1164 # where it is.
1165 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001166 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001167 data.declarations.pop(0)
1168
Larry Hastings31826802013-10-19 00:09:25 -07001169 template_dict = {}
1170
1171 full_name = f.full_name
1172 template_dict['full_name'] = full_name
1173
Larry Hastings5c661892014-01-24 06:17:25 -08001174 if new_or_init:
1175 name = f.cls.name
1176 else:
1177 name = f.name
1178
Larry Hastings31826802013-10-19 00:09:25 -07001179 template_dict['name'] = name
1180
Larry Hastings8666e652014-01-12 14:12:59 -08001181 if f.c_basename:
1182 c_basename = f.c_basename
1183 else:
1184 fields = full_name.split(".")
1185 if fields[-1] == '__new__':
1186 fields.pop()
1187 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001188
Larry Hastings31826802013-10-19 00:09:25 -07001189 template_dict['c_basename'] = c_basename
1190
1191 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1192 template_dict['methoddef_name'] = methoddef_name
1193
1194 template_dict['docstring'] = self.docstring_for_c_string(f)
1195
Larry Hastingsc2047262014-01-25 20:43:29 -08001196 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001197 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001198
Larry Hastings31826802013-10-19 00:09:25 -07001199 f.return_converter.render(f, data)
1200 template_dict['impl_return_type'] = f.return_converter.type
1201
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001202 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001203 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001204 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001205 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1206 template_dict['format_units'] = ''.join(data.format_units)
1207 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1208 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1209 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001210 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1211 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001212 template_dict['return_value'] = data.return_value
1213
Larry Hastings5c661892014-01-24 06:17:25 -08001214 # used by unpack tuple code generator
1215 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1216 unpack_min = first_optional
1217 unpack_max = len(selfless)
1218 template_dict['unpack_min'] = str(unpack_min)
1219 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001220
Larry Hastingsbebf7352014-01-17 17:47:17 -08001221 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001222 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001223
Larry Hastings0759f842015-04-03 13:09:02 -07001224 # buffers, not destination
1225 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001226 template = templates[name]
1227 if has_option_groups:
1228 template = linear_format(template,
1229 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001230 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001231 declarations=template_dict['declarations'],
1232 return_conversion=template_dict['return_conversion'],
1233 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001234 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001235 cleanup=template_dict['cleanup'],
1236 )
Larry Hastings31826802013-10-19 00:09:25 -07001237
Larry Hastingsbebf7352014-01-17 17:47:17 -08001238 # Only generate the "exit:" label
1239 # if we have any gotos
1240 need_exit_label = "goto exit;" in template
1241 template = linear_format(template,
1242 exit_label="exit:" if need_exit_label else ''
1243 )
Larry Hastings31826802013-10-19 00:09:25 -07001244
Larry Hastingsbebf7352014-01-17 17:47:17 -08001245 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001246
Larry Hastings89964c42015-04-14 18:07:59 -04001247 # mild hack:
1248 # reflow long impl declarations
1249 if name in {"impl_prototype", "impl_definition"}:
1250 s = wrap_declarations(s)
1251
Larry Hastingsbebf7352014-01-17 17:47:17 -08001252 if clinic.line_prefix:
1253 s = indent_all_lines(s, clinic.line_prefix)
1254 if clinic.line_suffix:
1255 s = suffix_all_lines(s, clinic.line_suffix)
1256
1257 destination.append(s)
1258
1259 return clinic.get_destination('block').dump()
1260
Larry Hastings31826802013-10-19 00:09:25 -07001261
1262
Larry Hastings5c661892014-01-24 06:17:25 -08001263
Larry Hastings31826802013-10-19 00:09:25 -07001264@contextlib.contextmanager
1265def OverrideStdioWith(stdout):
1266 saved_stdout = sys.stdout
1267 sys.stdout = stdout
1268 try:
1269 yield
1270 finally:
1271 assert sys.stdout is stdout
1272 sys.stdout = saved_stdout
1273
1274
Larry Hastings2623c8c2014-02-08 22:15:29 -08001275def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001276 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001277 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001278 pattern = r'{}({}){}'
1279 if whole_line:
1280 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001281 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1282 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001283
1284
1285class Block:
1286 r"""
1287 Represents a single block of text embedded in
1288 another file. If dsl_name is None, the block represents
1289 verbatim text, raw original text from the file, in
1290 which case "input" will be the only non-false member.
1291 If dsl_name is not None, the block represents a Clinic
1292 block.
1293
1294 input is always str, with embedded \n characters.
1295 input represents the original text from the file;
1296 if it's a Clinic block, it is the original text with
1297 the body_prefix and redundant leading whitespace removed.
1298
1299 dsl_name is either str or None. If str, it's the text
1300 found on the start line of the block between the square
1301 brackets.
1302
1303 signatures is either list or None. If it's a list,
1304 it may only contain clinic.Module, clinic.Class, and
1305 clinic.Function objects. At the moment it should
1306 contain at most one of each.
1307
1308 output is either str or None. If str, it's the output
1309 from this block, with embedded '\n' characters.
1310
1311 indent is either str or None. It's the leading whitespace
1312 that was found on every line of input. (If body_prefix is
1313 not empty, this is the indent *after* removing the
1314 body_prefix.)
1315
1316 preindent is either str or None. It's the whitespace that
1317 was found in front of every line of input *before* the
1318 "body_prefix" (see the Language object). If body_prefix
1319 is empty, preindent must always be empty too.
1320
1321 To illustrate indent and preindent: Assume that '_'
1322 represents whitespace. If the block processed was in a
1323 Python file, and looked like this:
1324 ____#/*[python]
1325 ____#__for a in range(20):
1326 ____#____print(a)
1327 ____#[python]*/
1328 "preindent" would be "____" and "indent" would be "__".
1329
1330 """
1331 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1332 assert isinstance(input, str)
1333 self.input = input
1334 self.dsl_name = dsl_name
1335 self.signatures = signatures or []
1336 self.output = output
1337 self.indent = indent
1338 self.preindent = preindent
1339
Larry Hastings581ee362014-01-28 05:00:08 -08001340 def __repr__(self):
1341 dsl_name = self.dsl_name or "text"
1342 def summarize(s):
1343 s = repr(s)
1344 if len(s) > 30:
1345 return s[:26] + "..." + s[0]
1346 return s
1347 return "".join((
1348 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1349
Larry Hastings31826802013-10-19 00:09:25 -07001350
1351class BlockParser:
1352 """
1353 Block-oriented parser for Argument Clinic.
1354 Iterator, yields Block objects.
1355 """
1356
1357 def __init__(self, input, language, *, verify=True):
1358 """
1359 "input" should be a str object
1360 with embedded \n characters.
1361
1362 "language" should be a Language object.
1363 """
1364 language.validate()
1365
1366 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1367 self.block_start_line_number = self.line_number = 0
1368
1369 self.language = language
1370 before, _, after = language.start_line.partition('{dsl_name}')
1371 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001372 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001373 self.start_re = create_regex(before, after)
1374 self.verify = verify
1375 self.last_checksum_re = None
1376 self.last_dsl_name = None
1377 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001378 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001379
1380 def __iter__(self):
1381 return self
1382
1383 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001384 while True:
1385 if not self.input:
1386 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001387
Larry Hastingsbebf7352014-01-17 17:47:17 -08001388 if self.dsl_name:
1389 return_value = self.parse_clinic_block(self.dsl_name)
1390 self.dsl_name = None
1391 self.first_block = False
1392 return return_value
1393 block = self.parse_verbatim_block()
1394 if self.first_block and not block.input:
1395 continue
1396 self.first_block = False
1397 return block
1398
Larry Hastings31826802013-10-19 00:09:25 -07001399
1400 def is_start_line(self, line):
1401 match = self.start_re.match(line.lstrip())
1402 return match.group(1) if match else None
1403
Larry Hastingse1b82532014-07-27 16:22:20 +02001404 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001405 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001406 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001407 if not lookahead:
1408 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001409 return line
Larry Hastings31826802013-10-19 00:09:25 -07001410
1411 def parse_verbatim_block(self):
1412 add, output = text_accumulator()
1413 self.block_start_line_number = self.line_number
1414
1415 while self.input:
1416 line = self._line()
1417 dsl_name = self.is_start_line(line)
1418 if dsl_name:
1419 self.dsl_name = dsl_name
1420 break
1421 add(line)
1422
1423 return Block(output())
1424
1425 def parse_clinic_block(self, dsl_name):
1426 input_add, input_output = text_accumulator()
1427 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001428 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001429 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1430
Larry Hastings90261132014-01-07 12:21:08 -08001431 def is_stop_line(line):
1432 # make sure to recognize stop line even if it
1433 # doesn't end with EOL (it could be the very end of the file)
1434 if not line.startswith(stop_line):
1435 return False
1436 remainder = line[len(stop_line):]
1437 return (not remainder) or remainder.isspace()
1438
Larry Hastings31826802013-10-19 00:09:25 -07001439 # consume body of program
1440 while self.input:
1441 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001442 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001443 break
1444 if body_prefix:
1445 line = line.lstrip()
1446 assert line.startswith(body_prefix)
1447 line = line[len(body_prefix):]
1448 input_add(line)
1449
1450 # consume output and checksum line, if present.
1451 if self.last_dsl_name == dsl_name:
1452 checksum_re = self.last_checksum_re
1453 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001454 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1455 assert _ == '{arguments}'
1456 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001457 self.last_dsl_name = dsl_name
1458 self.last_checksum_re = checksum_re
1459
1460 # scan forward for checksum line
1461 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001462 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001463 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001464 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001465 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001466 arguments = match.group(1) if match else None
1467 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001468 break
1469 output_add(line)
1470 if self.is_start_line(line):
1471 break
1472
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001473 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001474 if arguments:
1475 d = {}
1476 for field in shlex.split(arguments):
1477 name, equals, value = field.partition('=')
1478 if not equals:
1479 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1480 d[name.strip()] = value.strip()
1481
Larry Hastings31826802013-10-19 00:09:25 -07001482 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001483 if 'input' in d:
1484 checksum = d['output']
1485 input_checksum = d['input']
1486 else:
1487 checksum = d['checksum']
1488 input_checksum = None
1489
1490 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001491 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001492 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1493 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001494 "the end marker,\n"
1495 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001496 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001497 else:
1498 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001499 output_lines = output.splitlines(keepends=True)
1500 self.line_number -= len(output_lines)
1501 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001502 output = None
1503
1504 return Block(input_output(), dsl_name, output=output)
1505
1506
1507class BlockPrinter:
1508
1509 def __init__(self, language, f=None):
1510 self.language = language
1511 self.f = f or io.StringIO()
1512
1513 def print_block(self, block):
1514 input = block.input
1515 output = block.output
1516 dsl_name = block.dsl_name
1517 write = self.f.write
1518
Larry Hastings31826802013-10-19 00:09:25 -07001519 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1520
1521 if not dsl_name:
1522 write(input)
1523 return
1524
1525 write(self.language.start_line.format(dsl_name=dsl_name))
1526 write("\n")
1527
1528 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1529 if not body_prefix:
1530 write(input)
1531 else:
1532 for line in input.split('\n'):
1533 write(body_prefix)
1534 write(line)
1535 write("\n")
1536
1537 write(self.language.stop_line.format(dsl_name=dsl_name))
1538 write("\n")
1539
Larry Hastings581ee362014-01-28 05:00:08 -08001540 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001541 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001542 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001543 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001544 output += '\n'
1545 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001546
Larry Hastings581ee362014-01-28 05:00:08 -08001547 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1548 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001549 write("\n")
1550
Larry Hastingsbebf7352014-01-17 17:47:17 -08001551 def write(self, text):
1552 self.f.write(text)
1553
1554
Larry Hastings0759f842015-04-03 13:09:02 -07001555class BufferSeries:
1556 """
1557 Behaves like a "defaultlist".
1558 When you ask for an index that doesn't exist yet,
1559 the object grows the list until that item exists.
1560 So o[n] will always work.
1561
1562 Supports negative indices for actual items.
1563 e.g. o[-1] is an element immediately preceding o[0].
1564 """
1565
1566 def __init__(self):
1567 self._start = 0
1568 self._array = []
1569 self._constructor = _text_accumulator
1570
1571 def __getitem__(self, i):
1572 i -= self._start
1573 if i < 0:
1574 self._start += i
1575 prefix = [self._constructor() for x in range(-i)]
1576 self._array = prefix + self._array
1577 i = 0
1578 while i >= len(self._array):
1579 self._array.append(self._constructor())
1580 return self._array[i]
1581
1582 def clear(self):
1583 for ta in self._array:
1584 ta._text.clear()
1585
1586 def dump(self):
1587 texts = [ta.output() for ta in self._array]
1588 return "".join(texts)
1589
1590
Larry Hastingsbebf7352014-01-17 17:47:17 -08001591class Destination:
1592 def __init__(self, name, type, clinic, *args):
1593 self.name = name
1594 self.type = type
1595 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001596 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001597 if type not in valid_types:
1598 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1599 extra_arguments = 1 if type == "file" else 0
1600 if len(args) < extra_arguments:
1601 fail("Not enough arguments for destination " + name + " new " + type)
1602 if len(args) > extra_arguments:
1603 fail("Too many arguments for destination " + name + " new " + type)
1604 if type =='file':
1605 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001606 filename = clinic.filename
1607 d['path'] = filename
1608 dirname, basename = os.path.split(filename)
1609 if not dirname:
1610 dirname = '.'
1611 d['dirname'] = dirname
1612 d['basename'] = basename
1613 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001614 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001615
Larry Hastings0759f842015-04-03 13:09:02 -07001616 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001617
1618 def __repr__(self):
1619 if self.type == 'file':
1620 file_repr = " " + repr(self.filename)
1621 else:
1622 file_repr = ''
1623 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1624
1625 def clear(self):
1626 if self.type != 'buffer':
1627 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001628 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001629
1630 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001631 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001632
Larry Hastings31826802013-10-19 00:09:25 -07001633
1634# maps strings to Language objects.
1635# "languages" maps the name of the language ("C", "Python").
1636# "extensions" maps the file extension ("c", "py").
1637languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001638extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1639extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001640
1641
1642# maps strings to callables.
1643# these callables must be of the form:
1644# def foo(name, default, *, ...)
1645# The callable may have any number of keyword-only parameters.
1646# The callable must return a CConverter object.
1647# The callable should not call builtins.print.
1648converters = {}
1649
1650# maps strings to callables.
1651# these callables follow the same rules as those for "converters" above.
1652# note however that they will never be called with keyword-only parameters.
1653legacy_converters = {}
1654
1655
1656# maps strings to callables.
1657# these callables must be of the form:
1658# def foo(*, ...)
1659# The callable may have any number of keyword-only parameters.
1660# The callable must return a CConverter object.
1661# The callable should not call builtins.print.
1662return_converters = {}
1663
Larry Hastings7726ac92014-01-31 22:03:12 -08001664clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001665class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001666
1667 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001668preset block
1669everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001670methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001671docstring_prototype suppress
1672parser_prototype suppress
1673cpp_if suppress
1674cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001675
Larry Hastingsbebf7352014-01-17 17:47:17 -08001676preset original
1677everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001678methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001679docstring_prototype suppress
1680parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001681cpp_if suppress
1682cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001683
1684preset file
1685everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001686methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001687docstring_prototype suppress
1688parser_prototype suppress
1689impl_definition block
1690
1691preset buffer
1692everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001693methoddef_ifndef buffer 1
1694impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001695docstring_prototype suppress
1696impl_prototype suppress
1697parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001698
1699preset partial-buffer
1700everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001701methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001702docstring_prototype block
1703impl_prototype suppress
1704methoddef_define block
1705parser_prototype block
1706impl_definition block
1707
Larry Hastingsbebf7352014-01-17 17:47:17 -08001708"""
1709
Larry Hastings581ee362014-01-28 05:00:08 -08001710 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001711 # maps strings to Parser objects.
1712 # (instantiated from the "parsers" global.)
1713 self.parsers = {}
1714 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001715 if printer:
1716 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001717 self.printer = printer or BlockPrinter(language)
1718 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001719 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001720 self.filename = filename
1721 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001722 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001723 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001724
Larry Hastingsbebf7352014-01-17 17:47:17 -08001725 self.line_prefix = self.line_suffix = ''
1726
1727 self.destinations = {}
1728 self.add_destination("block", "buffer")
1729 self.add_destination("suppress", "suppress")
1730 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001731 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001732 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001733
Larry Hastings0759f842015-04-03 13:09:02 -07001734 d = self.get_destination_buffer
1735 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001736 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001737 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001738 ('docstring_definition', d('file')),
1739 ('methoddef_define', d('file')),
1740 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001741 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001742 ('parser_definition', d('file')),
1743 ('cpp_endif', d('file')),
1744 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001745 ('impl_definition', d('block')),
1746 ))
1747
Larry Hastings0759f842015-04-03 13:09:02 -07001748 self.destination_buffers_stack = []
1749 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001750
1751 self.presets = {}
1752 preset = None
1753 for line in self.presets_text.strip().split('\n'):
1754 line = line.strip()
1755 if not line:
1756 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001757 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001758 if name == 'preset':
1759 self.presets[value] = preset = collections.OrderedDict()
1760 continue
1761
Larry Hastings0759f842015-04-03 13:09:02 -07001762 if len(options):
1763 index = int(options[0])
1764 else:
1765 index = 0
1766 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001767
1768 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001769 for name in self.destination_buffers:
1770 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001771 continue
1772
Larry Hastings0759f842015-04-03 13:09:02 -07001773 assert name in self.destination_buffers
1774 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001775
Larry Hastings31826802013-10-19 00:09:25 -07001776 global clinic
1777 clinic = self
1778
Larry Hastingsbebf7352014-01-17 17:47:17 -08001779 def add_destination(self, name, type, *args):
1780 if name in self.destinations:
1781 fail("Destination already exists: " + repr(name))
1782 self.destinations[name] = Destination(name, type, self, *args)
1783
Larry Hastings0759f842015-04-03 13:09:02 -07001784 def get_destination(self, name):
1785 d = self.destinations.get(name)
1786 if not d:
1787 fail("Destination does not exist: " + repr(name))
1788 return d
1789
1790 def get_destination_buffer(self, name, item=0):
1791 d = self.get_destination(name)
1792 return d.buffers[item]
1793
Larry Hastings31826802013-10-19 00:09:25 -07001794 def parse(self, input):
1795 printer = self.printer
1796 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1797 for block in self.block_parser:
1798 dsl_name = block.dsl_name
1799 if dsl_name:
1800 if dsl_name not in self.parsers:
1801 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1802 self.parsers[dsl_name] = parsers[dsl_name](self)
1803 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001804 try:
1805 parser.parse(block)
1806 except Exception:
1807 fail('Exception raised during parsing:\n' +
1808 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001809 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001810
1811 second_pass_replacements = {}
1812
Larry Hastings0759f842015-04-03 13:09:02 -07001813 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001814 for name, destination in self.destinations.items():
1815 if destination.type == 'suppress':
1816 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001817 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001818
1819 if output:
1820
1821 block = Block("", dsl_name="clinic", output=output)
1822
1823 if destination.type == 'buffer':
1824 block.input = "dump " + name + "\n"
1825 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1826 printer.write("\n")
1827 printer.print_block(block)
1828 continue
1829
1830 if destination.type == 'file':
1831 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001832 dirname = os.path.dirname(destination.filename)
1833 try:
1834 os.makedirs(dirname)
1835 except FileExistsError:
1836 if not os.path.isdir(dirname):
1837 fail("Can't write to destination {}, "
1838 "can't make directory {}!".format(
1839 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001840 if self.verify:
1841 with open(destination.filename, "rt") as f:
1842 parser_2 = BlockParser(f.read(), language=self.language)
1843 blocks = list(parser_2)
1844 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1845 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001846 except FileNotFoundError:
1847 pass
1848
1849 block.input = 'preserve\n'
1850 printer_2 = BlockPrinter(self.language)
1851 printer_2.print_block(block)
1852 with open(destination.filename, "wt") as f:
1853 f.write(printer_2.f.getvalue())
1854 continue
1855 text = printer.f.getvalue()
1856
1857 if second_pass_replacements:
1858 printer_2 = BlockPrinter(self.language)
1859 parser_2 = BlockParser(text, self.language)
1860 changed = False
1861 for block in parser_2:
1862 if block.dsl_name:
1863 for id, replacement in second_pass_replacements.items():
1864 if id in block.output:
1865 changed = True
1866 block.output = block.output.replace(id, replacement)
1867 printer_2.print_block(block)
1868 if changed:
1869 text = printer_2.f.getvalue()
1870
1871 return text
1872
Larry Hastings31826802013-10-19 00:09:25 -07001873
1874 def _module_and_class(self, fields):
1875 """
1876 fields should be an iterable of field names.
1877 returns a tuple of (module, class).
1878 the module object could actually be self (a clinic object).
1879 this function is only ever used to find the parent of where
1880 a new class/module should go.
1881 """
1882 in_classes = False
1883 parent = module = self
1884 cls = None
1885 so_far = []
1886
1887 for field in fields:
1888 so_far.append(field)
1889 if not in_classes:
1890 child = parent.modules.get(field)
1891 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001892 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001893 continue
1894 in_classes = True
1895 if not hasattr(parent, 'classes'):
1896 return module, cls
1897 child = parent.classes.get(field)
1898 if not child:
1899 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1900 cls = parent = child
1901
1902 return module, cls
1903
1904
Larry Hastings581ee362014-01-28 05:00:08 -08001905def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001906 extension = os.path.splitext(filename)[1][1:]
1907 if not extension:
1908 fail("Can't extract file type for file " + repr(filename))
1909
1910 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001911 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001912 except KeyError:
1913 fail("Can't identify file type for file " + repr(filename))
1914
Larry Hastings31826802013-10-19 00:09:25 -07001915 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001916 raw = f.read()
1917
Larry Hastings2623c8c2014-02-08 22:15:29 -08001918 # exit quickly if there are no clinic markers in the file
1919 find_start_re = BlockParser("", language).find_start_re
1920 if not find_start_re.search(raw):
1921 return
1922
1923 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001924 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001925 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001926 return
Larry Hastings31826802013-10-19 00:09:25 -07001927
1928 directory = os.path.dirname(filename) or '.'
1929
1930 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001931 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001932 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1933 with open(tmpfilename, "wb") as f:
1934 f.write(bytes)
1935 os.replace(tmpfilename, output or filename)
1936
1937
Larry Hastings581ee362014-01-28 05:00:08 -08001938def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001939 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001940 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1941 if length:
1942 s = s[:length]
1943 return s
Larry Hastings31826802013-10-19 00:09:25 -07001944
1945
1946
1947
1948class PythonParser:
1949 def __init__(self, clinic):
1950 pass
1951
1952 def parse(self, block):
1953 s = io.StringIO()
1954 with OverrideStdioWith(s):
1955 exec(block.input)
1956 block.output = s.getvalue()
1957
1958
1959class Module:
1960 def __init__(self, name, module=None):
1961 self.name = name
1962 self.module = self.parent = module
1963
1964 self.modules = collections.OrderedDict()
1965 self.classes = collections.OrderedDict()
1966 self.functions = []
1967
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001968 def __repr__(self):
1969 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1970
Larry Hastings31826802013-10-19 00:09:25 -07001971class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001972 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001973 self.name = name
1974 self.module = module
1975 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001976 self.typedef = typedef
1977 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001978 self.parent = cls or module
1979
1980 self.classes = collections.OrderedDict()
1981 self.functions = []
1982
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001983 def __repr__(self):
1984 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1985
Larry Hastings8666e652014-01-12 14:12:59 -08001986unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001987
Larry Hastings8666e652014-01-12 14:12:59 -08001988__abs__
1989__add__
1990__and__
1991__bytes__
1992__call__
1993__complex__
1994__delitem__
1995__divmod__
1996__eq__
1997__float__
1998__floordiv__
1999__ge__
2000__getattr__
2001__getattribute__
2002__getitem__
2003__gt__
2004__hash__
2005__iadd__
2006__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08002007__ifloordiv__
2008__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002009__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002010__imod__
2011__imul__
2012__index__
2013__int__
2014__invert__
2015__ior__
2016__ipow__
2017__irshift__
2018__isub__
2019__iter__
2020__itruediv__
2021__ixor__
2022__le__
2023__len__
2024__lshift__
2025__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002026__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002027__mod__
2028__mul__
2029__neg__
2030__new__
2031__next__
2032__or__
2033__pos__
2034__pow__
2035__radd__
2036__rand__
2037__rdivmod__
2038__repr__
2039__rfloordiv__
2040__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002041__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002042__rmod__
2043__rmul__
2044__ror__
2045__round__
2046__rpow__
2047__rrshift__
2048__rshift__
2049__rsub__
2050__rtruediv__
2051__rxor__
2052__setattr__
2053__setitem__
2054__str__
2055__sub__
2056__truediv__
2057__xor__
2058
2059""".strip().split())
2060
2061
Larry Hastings5c661892014-01-24 06:17:25 -08002062INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2063INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2064""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002065
2066class Function:
2067 """
2068 Mutable duck type for inspect.Function.
2069
2070 docstring - a str containing
2071 * embedded line breaks
2072 * text outdented to the left margin
2073 * no trailing whitespace.
2074 It will always be true that
2075 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2076 """
2077
2078 def __init__(self, parameters=None, *, name,
2079 module, cls=None, c_basename=None,
2080 full_name=None,
2081 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002082 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002083 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002084 self.parameters = parameters or collections.OrderedDict()
2085 self.return_annotation = return_annotation
2086 self.name = name
2087 self.full_name = full_name
2088 self.module = module
2089 self.cls = cls
2090 self.parent = cls or module
2091 self.c_basename = c_basename
2092 self.return_converter = return_converter
2093 self.docstring = docstring or ''
2094 self.kind = kind
2095 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002096 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002097 # docstring_only means "don't generate a machine-readable
2098 # signature, just a normal docstring". it's True for
2099 # functions with optional groups because we can't represent
2100 # those accurately with inspect.Signature in 3.4.
2101 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002102
Larry Hastings7726ac92014-01-31 22:03:12 -08002103 self.rendered_parameters = None
2104
2105 __render_parameters__ = None
2106 @property
2107 def render_parameters(self):
2108 if not self.__render_parameters__:
2109 self.__render_parameters__ = l = []
2110 for p in self.parameters.values():
2111 p = p.copy()
2112 p.converter.pre_render()
2113 l.append(p)
2114 return self.__render_parameters__
2115
Larry Hastingsebdcb502013-11-23 14:54:00 -08002116 @property
2117 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002118 if self.kind in (METHOD_INIT, METHOD_NEW):
2119 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002120 flags = []
2121 if self.kind == CLASS_METHOD:
2122 flags.append('METH_CLASS')
2123 elif self.kind == STATIC_METHOD:
2124 flags.append('METH_STATIC')
2125 else:
2126 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2127 if self.coexist:
2128 flags.append('METH_COEXIST')
2129 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002130
2131 def __repr__(self):
2132 return '<clinic.Function ' + self.name + '>'
2133
Larry Hastings7726ac92014-01-31 22:03:12 -08002134 def copy(self, **overrides):
2135 kwargs = {
2136 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2137 'cls': self.cls, 'c_basename': self.c_basename,
2138 'full_name': self.full_name,
2139 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2140 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002141 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002142 }
2143 kwargs.update(overrides)
2144 f = Function(**kwargs)
2145
2146 parameters = collections.OrderedDict()
2147 for name, value in f.parameters.items():
2148 value = value.copy(function=f)
2149 parameters[name] = value
2150 f.parameters = parameters
2151 return f
2152
Larry Hastings31826802013-10-19 00:09:25 -07002153
2154class Parameter:
2155 """
2156 Mutable duck type of inspect.Parameter.
2157 """
2158
2159 def __init__(self, name, kind, *, default=_empty,
2160 function, converter, annotation=_empty,
2161 docstring=None, group=0):
2162 self.name = name
2163 self.kind = kind
2164 self.default = default
2165 self.function = function
2166 self.converter = converter
2167 self.annotation = annotation
2168 self.docstring = docstring or ''
2169 self.group = group
2170
2171 def __repr__(self):
2172 return '<clinic.Parameter ' + self.name + '>'
2173
2174 def is_keyword_only(self):
2175 return self.kind == inspect.Parameter.KEYWORD_ONLY
2176
Larry Hastings2623c8c2014-02-08 22:15:29 -08002177 def is_positional_only(self):
2178 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2179
Larry Hastings7726ac92014-01-31 22:03:12 -08002180 def copy(self, **overrides):
2181 kwargs = {
2182 'name': self.name, 'kind': self.kind, 'default':self.default,
2183 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2184 'docstring': self.docstring, 'group': self.group,
2185 }
2186 kwargs.update(overrides)
2187 if 'converter' not in overrides:
2188 converter = copy.copy(self.converter)
2189 converter.function = kwargs['function']
2190 kwargs['converter'] = converter
2191 return Parameter(**kwargs)
2192
2193
2194
2195class LandMine:
2196 # try to access any
2197 def __init__(self, message):
2198 self.__message__ = message
2199
2200 def __repr__(self):
2201 return '<LandMine ' + repr(self.__message__) + ">"
2202
2203 def __getattribute__(self, name):
2204 if name in ('__repr__', '__message__'):
2205 return super().__getattribute__(name)
2206 # raise RuntimeError(repr(name))
2207 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002208
Larry Hastings31826802013-10-19 00:09:25 -07002209
2210def add_c_converter(f, name=None):
2211 if not name:
2212 name = f.__name__
2213 if not name.endswith('_converter'):
2214 return f
2215 name = name[:-len('_converter')]
2216 converters[name] = f
2217 return f
2218
2219def add_default_legacy_c_converter(cls):
2220 # automatically add converter for default format unit
2221 # (but without stomping on the existing one if it's already
2222 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002223 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002224 (cls.format_unit not in legacy_converters)):
2225 legacy_converters[cls.format_unit] = cls
2226 return cls
2227
2228def add_legacy_c_converter(format_unit, **kwargs):
2229 """
2230 Adds a legacy converter.
2231 """
2232 def closure(f):
2233 if not kwargs:
2234 added_f = f
2235 else:
2236 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002237 if format_unit:
2238 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002239 return f
2240 return closure
2241
2242class CConverterAutoRegister(type):
2243 def __init__(cls, name, bases, classdict):
2244 add_c_converter(cls)
2245 add_default_legacy_c_converter(cls)
2246
2247class CConverter(metaclass=CConverterAutoRegister):
2248 """
2249 For the init function, self, name, function, and default
2250 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002251 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002252 """
2253
Larry Hastings7726ac92014-01-31 22:03:12 -08002254 # The C name to use for this variable.
2255 name = None
2256
2257 # The Python name to use for this variable.
2258 py_name = None
2259
Larry Hastings78cf85c2014-01-04 12:44:57 -08002260 # The C type to use for this variable.
2261 # 'type' should be a Python string specifying the type, e.g. "int".
2262 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002263 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002264
2265 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002266 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002267 # Or the magic value "unknown" if this value is a cannot be evaluated
2268 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2269 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002270 default = unspecified
2271
Larry Hastings4a55fc52014-01-12 11:09:57 -08002272 # If not None, default must be isinstance() of this type.
2273 # (You can also specify a tuple of types.)
2274 default_type = None
2275
Larry Hastings31826802013-10-19 00:09:25 -07002276 # "default" converted into a C value, as a string.
2277 # Or None if there is no default.
2278 c_default = None
2279
Larry Hastings2a727912014-01-16 11:32:01 -08002280 # "default" converted into a Python value, as a string.
2281 # Or None if there is no default.
2282 py_default = None
2283
Larry Hastingsabc716b2013-11-20 09:13:52 -08002284 # The default value used to initialize the C variable when
2285 # there is no default, but not specifying a default may
2286 # result in an "uninitialized variable" warning. This can
2287 # easily happen when using option groups--although
2288 # properly-written code won't actually use the variable,
2289 # the variable does get passed in to the _impl. (Ah, if
2290 # only dataflow analysis could inline the static function!)
2291 #
2292 # This value is specified as a string.
2293 # Every non-abstract subclass should supply a valid value.
2294 c_ignored_default = 'NULL'
2295
Larry Hastings31826802013-10-19 00:09:25 -07002296 # The C converter *function* to be used, if any.
2297 # (If this is not None, format_unit must be 'O&'.)
2298 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002299
Larry Hastings78cf85c2014-01-04 12:44:57 -08002300 # Should Argument Clinic add a '&' before the name of
2301 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002302 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002303
2304 # Should Argument Clinic add a '&' before the name of
2305 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002306 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002307
2308 #############################################################
2309 #############################################################
2310 ## You shouldn't need to read anything below this point to ##
2311 ## write your own converter functions. ##
2312 #############################################################
2313 #############################################################
2314
2315 # The "format unit" to specify for this variable when
2316 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2317 # Custom converters should always use the default value of 'O&'.
2318 format_unit = 'O&'
2319
2320 # What encoding do we want for this variable? Only used
2321 # by format units starting with 'e'.
2322 encoding = None
2323
Larry Hastings77561cc2014-01-07 12:13:13 -08002324 # Should this object be required to be a subclass of a specific type?
2325 # If not None, should be a string representing a pointer to a
2326 # PyTypeObject (e.g. "&PyUnicode_Type").
2327 # Only used by the 'O!' format unit (and the "object" converter).
2328 subclass_of = None
2329
Larry Hastings78cf85c2014-01-04 12:44:57 -08002330 # Do we want an adjacent '_length' variable for this variable?
2331 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002332 length = False
2333
Larry Hastings5c661892014-01-24 06:17:25 -08002334 # Should we show this parameter in the generated
2335 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002336 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002337 show_in_signature = True
2338
2339 # Overrides the name used in a text signature.
2340 # The name used for a "self" parameter must be one of
2341 # self, type, or module; however users can set their own.
2342 # This lets the self_converter overrule the user-settable
2343 # name, *just* for the text signature.
2344 # Only set by self_converter.
2345 signature_name = None
2346
2347 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002348 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 -07002349 self.name = name
Larry Hastings7726ac92014-01-31 22:03:12 -08002350 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002351
2352 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002353 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002354 if isinstance(self.default_type, type):
2355 types_str = self.default_type.__name__
2356 else:
2357 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2358 fail("{}: default value {!r} for field {} is not of type {}".format(
2359 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002360 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002361
Larry Hastingsb4705752014-01-18 21:54:15 -08002362 if c_default:
2363 self.c_default = c_default
2364 if py_default:
2365 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002366
Larry Hastings31826802013-10-19 00:09:25 -07002367 if annotation != unspecified:
2368 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002369
2370 # this is deliberate, to prevent you from caching information
2371 # about the function in the init.
2372 # (that breaks if we get cloned.)
2373 # so after this change we will noisily fail.
2374 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002375 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002376 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002377
2378 def converter_init(self):
2379 pass
2380
2381 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002382 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002383
Larry Hastings5c661892014-01-24 06:17:25 -08002384 def _render_self(self, parameter, data):
2385 self.parameter = parameter
2386 original_name = self.name
2387 name = ensure_legal_c_identifier(original_name)
2388
2389 # impl_arguments
2390 s = ("&" if self.impl_by_reference else "") + name
2391 data.impl_arguments.append(s)
2392 if self.length:
2393 data.impl_arguments.append(self.length_name())
2394
2395 # impl_parameters
2396 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2397 if self.length:
2398 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2399
2400 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002401 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002402 original_name = self.name
2403 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002404
2405 # declarations
2406 d = self.declaration()
2407 data.declarations.append(d)
2408
2409 # initializers
2410 initializers = self.initialize()
2411 if initializers:
2412 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2413
Larry Hastingsc2047262014-01-25 20:43:29 -08002414 # modifications
2415 modifications = self.modify()
2416 if modifications:
2417 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2418
Larry Hastings31826802013-10-19 00:09:25 -07002419 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002420 if parameter.is_positional_only():
2421 data.keywords.append('')
2422 else:
2423 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002424
2425 # format_units
2426 if self.is_optional() and '|' not in data.format_units:
2427 data.format_units.append('|')
2428 if parameter.is_keyword_only() and '$' not in data.format_units:
2429 data.format_units.append('$')
2430 data.format_units.append(self.format_unit)
2431
2432 # parse_arguments
2433 self.parse_argument(data.parse_arguments)
2434
Larry Hastings31826802013-10-19 00:09:25 -07002435 # cleanup
2436 cleanup = self.cleanup()
2437 if cleanup:
2438 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2439
Larry Hastings5c661892014-01-24 06:17:25 -08002440 def render(self, parameter, data):
2441 """
2442 parameter is a clinic.Parameter instance.
2443 data is a CRenderData instance.
2444 """
2445 self._render_self(parameter, data)
2446 self._render_non_self(parameter, data)
2447
Larry Hastingsebdcb502013-11-23 14:54:00 -08002448 def length_name(self):
2449 """Computes the name of the associated "length" variable."""
2450 if not self.length:
2451 return None
2452 return ensure_legal_c_identifier(self.name) + "_length"
2453
Larry Hastings31826802013-10-19 00:09:25 -07002454 # Why is this one broken out separately?
2455 # For "positional-only" function parsing,
2456 # which generates a bunch of PyArg_ParseTuple calls.
2457 def parse_argument(self, list):
2458 assert not (self.converter and self.encoding)
2459 if self.format_unit == 'O&':
2460 assert self.converter
2461 list.append(self.converter)
2462
2463 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002464 list.append(c_repr(self.encoding))
2465 elif self.subclass_of:
2466 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002467
Larry Hastingsebdcb502013-11-23 14:54:00 -08002468 legal_name = ensure_legal_c_identifier(self.name)
2469 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002470 list.append(s)
2471
Larry Hastingsebdcb502013-11-23 14:54:00 -08002472 if self.length:
2473 list.append("&" + self.length_name())
2474
Larry Hastings31826802013-10-19 00:09:25 -07002475 #
2476 # All the functions after here are intended as extension points.
2477 #
2478
2479 def simple_declaration(self, by_reference=False):
2480 """
2481 Computes the basic declaration of the variable.
2482 Used in computing the prototype declaration and the
2483 variable declaration.
2484 """
2485 prototype = [self.type]
2486 if by_reference or not self.type.endswith('*'):
2487 prototype.append(" ")
2488 if by_reference:
2489 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002490 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002491 return "".join(prototype)
2492
2493 def declaration(self):
2494 """
2495 The C statement to declare this variable.
2496 """
2497 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002498 default = self.c_default
2499 if not default and self.parameter.group:
2500 default = self.c_ignored_default
2501 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002502 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002503 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002504 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002505 if self.length:
2506 declaration.append('\nPy_ssize_clean_t ')
2507 declaration.append(self.length_name())
2508 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002509 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002510
2511 def initialize(self):
2512 """
2513 The C statements required to set up this variable before parsing.
2514 Returns a string containing this code indented at column 0.
2515 If no initialization is necessary, returns an empty string.
2516 """
2517 return ""
2518
Larry Hastingsc2047262014-01-25 20:43:29 -08002519 def modify(self):
2520 """
2521 The C statements required to modify this variable after parsing.
2522 Returns a string containing this code indented at column 0.
2523 If no initialization is necessary, returns an empty string.
2524 """
2525 return ""
2526
Larry Hastings31826802013-10-19 00:09:25 -07002527 def cleanup(self):
2528 """
2529 The C statements required to clean up after this variable.
2530 Returns a string containing this code indented at column 0.
2531 If no cleanup is necessary, returns an empty string.
2532 """
2533 return ""
2534
Larry Hastings7726ac92014-01-31 22:03:12 -08002535 def pre_render(self):
2536 """
2537 A second initialization function, like converter_init,
2538 called just before rendering.
2539 You are permitted to examine self.function here.
2540 """
2541 pass
2542
Larry Hastings31826802013-10-19 00:09:25 -07002543
2544class bool_converter(CConverter):
2545 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002546 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002547 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002548 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002549
2550 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002551 if self.default is not unspecified:
2552 self.default = bool(self.default)
2553 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002554
2555class char_converter(CConverter):
2556 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002557 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002558 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002559 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002560
Larry Hastings4a55fc52014-01-12 11:09:57 -08002561 def converter_init(self):
Larry Hastings7f90cba2015-04-15 23:02:12 -04002562 if isinstance(self.default, self.default_type) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002563 fail("char_converter: illegal default value " + repr(self.default))
2564
2565
Larry Hastings31826802013-10-19 00:09:25 -07002566@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002567class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002568 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002569 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002570 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002571 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002572
2573 def converter_init(self, *, bitwise=False):
2574 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002575 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002576
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002577class byte_converter(unsigned_char_converter): pass
2578
Larry Hastings31826802013-10-19 00:09:25 -07002579class short_converter(CConverter):
2580 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002581 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002582 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002583 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002584
2585class unsigned_short_converter(CConverter):
2586 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002587 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002588 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002589 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002590
2591 def converter_init(self, *, bitwise=False):
2592 if not bitwise:
2593 fail("Unsigned shorts must be bitwise (for now).")
2594
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002595@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002596class int_converter(CConverter):
2597 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002598 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002599 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002600 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002601
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002602 def converter_init(self, *, accept={int}, type=None):
2603 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002604 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002605 elif accept != {int}:
2606 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002607 if type != None:
2608 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002609
2610class unsigned_int_converter(CConverter):
2611 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002612 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002613 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002614 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002615
2616 def converter_init(self, *, bitwise=False):
2617 if not bitwise:
2618 fail("Unsigned ints must be bitwise (for now).")
2619
2620class long_converter(CConverter):
2621 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002622 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002623 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002624 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002625
2626class unsigned_long_converter(CConverter):
2627 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002628 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002629 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002630 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002631
2632 def converter_init(self, *, bitwise=False):
2633 if not bitwise:
2634 fail("Unsigned longs must be bitwise (for now).")
2635
Benjamin Petersoncc854492016-09-08 09:29:11 -07002636class long_long_converter(CConverter):
2637 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002638 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002639 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002640 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002641
Benjamin Petersoncc854492016-09-08 09:29:11 -07002642class unsigned_long_long_converter(CConverter):
2643 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002644 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002645 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002646 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002647
2648 def converter_init(self, *, bitwise=False):
2649 if not bitwise:
Benjamin Petersoncc854492016-09-08 09:29:11 -07002650 fail("Unsigned long long must be bitwise (for now).")
Larry Hastings31826802013-10-19 00:09:25 -07002651
2652class Py_ssize_t_converter(CConverter):
2653 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002654 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002655 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002656 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002657
2658
2659class float_converter(CConverter):
2660 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002661 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002662 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002663 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002664
2665class double_converter(CConverter):
2666 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002667 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002668 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002669 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002670
2671
2672class Py_complex_converter(CConverter):
2673 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002674 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002675 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002676 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002677
2678
2679class object_converter(CConverter):
2680 type = 'PyObject *'
2681 format_unit = 'O'
2682
Larry Hastings4a55fc52014-01-12 11:09:57 -08002683 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2684 if converter:
2685 if subclass_of:
2686 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2687 self.format_unit = 'O&'
2688 self.converter = converter
2689 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002690 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002691 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002692
Larry Hastings77561cc2014-01-07 12:13:13 -08002693 if type is not None:
2694 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002695
2696
Larry Hastings7f90cba2015-04-15 23:02:12 -04002697#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002698# We define three conventions for buffer types in the 'accept' argument:
2699#
2700# buffer : any object supporting the buffer interface
2701# rwbuffer: any object supporting the buffer interface, but must be writeable
2702# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04002703#
2704
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002705class buffer: pass
2706class rwbuffer: pass
2707class robuffer: pass
2708
Larry Hastings38337d12015-05-07 23:30:09 -07002709def str_converter_key(types, encoding, zeroes):
2710 return (frozenset(types), bool(encoding), bool(zeroes))
2711
2712str_converter_argument_map = {}
2713
Larry Hastings31826802013-10-19 00:09:25 -07002714class str_converter(CConverter):
2715 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002716 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002717 format_unit = 's'
2718
Larry Hastings38337d12015-05-07 23:30:09 -07002719 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002720
Larry Hastings38337d12015-05-07 23:30:09 -07002721 key = str_converter_key(accept, encoding, zeroes)
2722 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002723 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07002724 fail("str_converter: illegal combination of arguments", key)
2725
Larry Hastingsebdcb502013-11-23 14:54:00 -08002726 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07002727 self.length = bool(zeroes)
2728 if encoding:
2729 if self.default not in (Null, None, unspecified):
2730 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
2731 self.encoding = encoding
2732 self.type = 'char *'
2733 # sorry, clinic can't support preallocated buffers
2734 # for es# and et#
2735 self.c_default = "NULL"
2736
2737 def cleanup(self):
2738 if self.encoding:
2739 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002740 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07002741
2742#
2743# This is the fourth or fifth rewrite of registering all the
2744# crazy string converter format units. Previous approaches hid
2745# bugs--generally mismatches between the semantics of the format
2746# unit and the arguments necessary to represent those semantics
2747# properly. Hopefully with this approach we'll get it 100% right.
2748#
2749# The r() function (short for "register") both registers the
2750# mapping from arguments to format unit *and* registers the
2751# legacy C converter for that format unit.
2752#
2753def r(format_unit, *, accept, encoding=False, zeroes=False):
2754 if not encoding and format_unit != 's':
2755 # add the legacy c converters here too.
2756 #
2757 # note: add_legacy_c_converter can't work for
2758 # es, es#, et, or et#
2759 # because of their extra encoding argument
2760 #
2761 # also don't add the converter for 's' because
2762 # the metaclass for CConverter adds it for us.
2763 kwargs = {}
2764 if accept != {str}:
2765 kwargs['accept'] = accept
2766 if zeroes:
2767 kwargs['zeroes'] = True
2768 added_f = functools.partial(str_converter, **kwargs)
2769 legacy_converters[format_unit] = added_f
2770
2771 d = str_converter_argument_map
2772 key = str_converter_key(accept, encoding, zeroes)
2773 if key in d:
2774 sys.exit("Duplicate keys specified for str_converter_argument_map!")
2775 d[key] = format_unit
2776
2777r('es', encoding=True, accept={str})
2778r('es#', encoding=True, zeroes=True, accept={str})
2779r('et', encoding=True, accept={bytes, bytearray, str})
2780r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
2781r('s', accept={str})
2782r('s#', zeroes=True, accept={robuffer, str})
2783r('y', accept={robuffer})
2784r('y#', zeroes=True, accept={robuffer})
2785r('z', accept={str, NoneType})
2786r('z#', zeroes=True, accept={robuffer, str, NoneType})
2787del r
Larry Hastings31826802013-10-19 00:09:25 -07002788
2789
2790class PyBytesObject_converter(CConverter):
2791 type = 'PyBytesObject *'
2792 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002793 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07002794
2795class PyByteArrayObject_converter(CConverter):
2796 type = 'PyByteArrayObject *'
2797 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002798 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07002799
2800class unicode_converter(CConverter):
2801 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002802 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002803 format_unit = 'U'
2804
Larry Hastings38337d12015-05-07 23:30:09 -07002805@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002806@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07002807@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07002808class Py_UNICODE_converter(CConverter):
2809 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002810 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002811 format_unit = 'u'
2812
Larry Hastings38337d12015-05-07 23:30:09 -07002813 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002814 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07002815 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002816 format_unit += '#'
2817 self.length = True
2818 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002819
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002820@add_legacy_c_converter('s*', accept={str, buffer})
2821@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
2822@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07002823class Py_buffer_converter(CConverter):
2824 type = 'Py_buffer'
2825 format_unit = 'y*'
2826 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002827 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002828
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002829 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002830 if self.default not in (unspecified, None):
2831 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002832
Larry Hastings3f144c22014-01-06 10:34:00 -08002833 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002834
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002835 if accept == {str, buffer, NoneType}:
2836 format_unit = 'z*'
2837 elif accept == {str, buffer}:
2838 format_unit = 's*'
2839 elif accept == {buffer}:
2840 format_unit = 'y*'
2841 elif accept == {rwbuffer}:
2842 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07002843 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002844 fail("Py_buffer_converter: illegal combination of arguments")
2845
2846 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002847
2848 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002849 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002850 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002851
2852
Larry Hastings5c661892014-01-24 06:17:25 -08002853def correct_name_for_self(f):
2854 if f.kind in (CALLABLE, METHOD_INIT):
2855 if f.cls:
2856 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03002857 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08002858 if f.kind == STATIC_METHOD:
2859 return "void *", "null"
2860 if f.kind in (CLASS_METHOD, METHOD_NEW):
2861 return "PyTypeObject *", "type"
2862 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2863
Larry Hastingsc2047262014-01-25 20:43:29 -08002864def required_type_for_self_for_parser(f):
2865 type, _ = correct_name_for_self(f)
2866 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2867 return type
2868 return None
2869
Larry Hastings5c661892014-01-24 06:17:25 -08002870
Larry Hastingsebdcb502013-11-23 14:54:00 -08002871class self_converter(CConverter):
2872 """
2873 A special-case converter:
2874 this is the default converter used for "self".
2875 """
Larry Hastings5c661892014-01-24 06:17:25 -08002876 type = None
2877 format_unit = ''
2878
Larry Hastings78cf85c2014-01-04 12:44:57 -08002879 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08002880 self.specified_type = type
2881
2882 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002883 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002884 default_type, default_name = correct_name_for_self(f)
2885 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08002886 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002887
Larry Hastings5c661892014-01-24 06:17:25 -08002888 kind = self.function.kind
2889 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2890
2891 if (kind == STATIC_METHOD) or new_or_init:
2892 self.show_in_signature = False
2893
2894 # tp_new (METHOD_NEW) functions are of type newfunc:
2895 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2896 # PyTypeObject is a typedef for struct _typeobject.
2897 #
2898 # tp_init (METHOD_INIT) functions are of type initproc:
2899 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2900 #
2901 # All other functions generated by Argument Clinic are stored in
2902 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2903 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2904 # However! We habitually cast these functions to PyCFunction,
2905 # since functions that accept keyword arguments don't fit this signature
2906 # but are stored there anyway. So strict type equality isn't important
2907 # for these functions.
2908 #
2909 # So:
2910 #
2911 # * The name of the first parameter to the impl and the parsing function will always
2912 # be self.name.
2913 #
2914 # * The type of the first parameter to the impl will always be of self.type.
2915 #
2916 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2917 # * The type of the first parameter to the parsing function is also self.type.
2918 # This means that if you step into the parsing function, your "self" parameter
2919 # is of the correct type, which may make debugging more pleasant.
2920 #
2921 # * Else if the function is tp_new (METHOD_NEW):
2922 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2923 # so the type signature of the function call is an exact match.
2924 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2925 # in the impl call.
2926 #
2927 # * Else if the function is tp_init (METHOD_INIT):
2928 # * The type of the first parameter to the parsing function is "PyObject *",
2929 # so the type signature of the function call is an exact match.
2930 # * If self.type != "PyObject *", we cast the first parameter to self.type
2931 # in the impl call.
2932
2933 @property
2934 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002935 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002936
Larry Hastingsebdcb502013-11-23 14:54:00 -08002937 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002938 """
2939 parameter is a clinic.Parameter instance.
2940 data is a CRenderData instance.
2941 """
2942 if self.function.kind == STATIC_METHOD:
2943 return
2944
2945 self._render_self(parameter, data)
2946
2947 if self.type != self.parser_type:
2948 # insert cast to impl_argument[0], aka self.
2949 # we know we're in the first slot in all the CRenderData lists,
2950 # because we render parameters in order, and self is always first.
2951 assert len(data.impl_arguments) == 1
2952 assert data.impl_arguments[0] == self.name
2953 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
2954
2955 def set_template_dict(self, template_dict):
2956 template_dict['self_name'] = self.name
2957 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08002958 kind = self.function.kind
2959 cls = self.function.cls
2960
2961 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
2962 if kind == METHOD_NEW:
2963 passed_in_type = self.name
2964 else:
2965 passed_in_type = 'Py_TYPE({})'.format(self.name)
2966
2967 line = '({passed_in_type} == {type_object}) &&\n '
2968 d = {
2969 'type_object': self.function.cls.type_object,
2970 'passed_in_type': passed_in_type
2971 }
2972 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002973
Larry Hastings31826802013-10-19 00:09:25 -07002974
2975
2976def add_c_return_converter(f, name=None):
2977 if not name:
2978 name = f.__name__
2979 if not name.endswith('_return_converter'):
2980 return f
2981 name = name[:-len('_return_converter')]
2982 return_converters[name] = f
2983 return f
2984
2985
2986class CReturnConverterAutoRegister(type):
2987 def __init__(cls, name, bases, classdict):
2988 add_c_return_converter(cls)
2989
2990class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2991
Larry Hastings78cf85c2014-01-04 12:44:57 -08002992 # The C type to use for this variable.
2993 # 'type' should be a Python string specifying the type, e.g. "int".
2994 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002995 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002996
2997 # The Python default value for this parameter, as a Python value.
2998 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002999 default = None
3000
Larry Hastings2a727912014-01-16 11:32:01 -08003001 def __init__(self, *, py_default=None, **kwargs):
3002 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07003003 try:
3004 self.return_converter_init(**kwargs)
3005 except TypeError as e:
3006 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
3007 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
3008
3009 def return_converter_init(self):
3010 pass
3011
3012 def declare(self, data, name="_return_value"):
3013 line = []
3014 add = line.append
3015 add(self.type)
3016 if not self.type.endswith('*'):
3017 add(' ')
3018 add(name + ';')
3019 data.declarations.append(''.join(line))
3020 data.return_value = name
3021
3022 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003023 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07003024
3025 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003026 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07003027
3028 def render(self, function, data):
3029 """
3030 function is a clinic.Function instance.
3031 data is a CRenderData instance.
3032 """
3033 pass
3034
3035add_c_return_converter(CReturnConverter, 'object')
3036
Larry Hastings78cf85c2014-01-04 12:44:57 -08003037class NoneType_return_converter(CReturnConverter):
3038 def render(self, function, data):
3039 self.declare(data)
3040 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003041if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003042 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003043}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003044return_value = Py_None;
3045Py_INCREF(Py_None);
3046'''.strip())
3047
Larry Hastings4a55fc52014-01-12 11:09:57 -08003048class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003049 type = 'int'
3050
3051 def render(self, function, data):
3052 self.declare(data)
3053 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003054 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003055
3056class long_return_converter(CReturnConverter):
3057 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003058 conversion_fn = 'PyLong_FromLong'
3059 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003060 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003061
3062 def render(self, function, data):
3063 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003064 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003065 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003066 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003067
Larry Hastings4a55fc52014-01-12 11:09:57 -08003068class int_return_converter(long_return_converter):
3069 type = 'int'
3070 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003071
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003072class init_return_converter(long_return_converter):
3073 """
3074 Special return converter for __init__ functions.
3075 """
3076 type = 'int'
3077 cast = '(long)'
3078
3079 def render(self, function, data):
3080 pass
3081
Larry Hastings4a55fc52014-01-12 11:09:57 -08003082class unsigned_long_return_converter(long_return_converter):
3083 type = 'unsigned long'
3084 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003085 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003086
3087class unsigned_int_return_converter(unsigned_long_return_converter):
3088 type = 'unsigned int'
3089 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003090 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003091
3092class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003093 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003094 conversion_fn = 'PyLong_FromSsize_t'
3095
3096class size_t_return_converter(long_return_converter):
3097 type = 'size_t'
3098 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003099 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003100
3101
3102class double_return_converter(CReturnConverter):
3103 type = 'double'
3104 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003105
3106 def render(self, function, data):
3107 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003108 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003109 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003110 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3111
3112class float_return_converter(double_return_converter):
3113 type = 'float'
3114 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003115
3116
3117class DecodeFSDefault_return_converter(CReturnConverter):
3118 type = 'char *'
3119
3120 def render(self, function, data):
3121 self.declare(data)
3122 self.err_occurred_if_null_pointer("_return_value", data)
3123 data.return_conversion.append(
3124 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
3125
3126
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003127def eval_ast_expr(node, globals, *, filename='-'):
3128 """
3129 Takes an ast.Expr node. Compiles and evaluates it.
3130 Returns the result of the expression.
3131
3132 globals represents the globals dict the expression
3133 should see. (There's no equivalent for "locals" here.)
3134 """
3135
3136 if isinstance(node, ast.Expr):
3137 node = node.value
3138
3139 node = ast.Expression(node)
3140 co = compile(node, filename, 'eval')
3141 fn = types.FunctionType(co, globals)
3142 return fn()
3143
3144
Larry Hastings31826802013-10-19 00:09:25 -07003145class IndentStack:
3146 def __init__(self):
3147 self.indents = []
3148 self.margin = None
3149
3150 def _ensure(self):
3151 if not self.indents:
3152 fail('IndentStack expected indents, but none are defined.')
3153
3154 def measure(self, line):
3155 """
3156 Returns the length of the line's margin.
3157 """
3158 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003159 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003160 stripped = line.lstrip()
3161 if not len(stripped):
3162 # we can't tell anything from an empty line
3163 # so just pretend it's indented like our current indent
3164 self._ensure()
3165 return self.indents[-1]
3166 return len(line) - len(stripped)
3167
3168 def infer(self, line):
3169 """
3170 Infer what is now the current margin based on this line.
3171 Returns:
3172 1 if we have indented (or this is the first margin)
3173 0 if the margin has not changed
3174 -N if we have dedented N times
3175 """
3176 indent = self.measure(line)
3177 margin = ' ' * indent
3178 if not self.indents:
3179 self.indents.append(indent)
3180 self.margin = margin
3181 return 1
3182 current = self.indents[-1]
3183 if indent == current:
3184 return 0
3185 if indent > current:
3186 self.indents.append(indent)
3187 self.margin = margin
3188 return 1
3189 # indent < current
3190 if indent not in self.indents:
3191 fail("Illegal outdent.")
3192 outdent_count = 0
3193 while indent != current:
3194 self.indents.pop()
3195 current = self.indents[-1]
3196 outdent_count -= 1
3197 self.margin = margin
3198 return outdent_count
3199
3200 @property
3201 def depth(self):
3202 """
3203 Returns how many margins are currently defined.
3204 """
3205 return len(self.indents)
3206
3207 def indent(self, line):
3208 """
3209 Indents a line by the currently defined margin.
3210 """
3211 return self.margin + line
3212
3213 def dedent(self, line):
3214 """
3215 Dedents a line by the currently defined margin.
3216 (The inverse of 'indent'.)
3217 """
3218 margin = self.margin
3219 indent = self.indents[-1]
3220 if not line.startswith(margin):
3221 fail('Cannot dedent, line does not start with the previous margin:')
3222 return line[indent:]
3223
3224
3225class DSLParser:
3226 def __init__(self, clinic):
3227 self.clinic = clinic
3228
3229 self.directives = {}
3230 for name in dir(self):
3231 # functions that start with directive_ are added to directives
3232 _, s, key = name.partition("directive_")
3233 if s:
3234 self.directives[key] = getattr(self, name)
3235
3236 # functions that start with at_ are too, with an @ in front
3237 _, s, key = name.partition("at_")
3238 if s:
3239 self.directives['@' + key] = getattr(self, name)
3240
3241 self.reset()
3242
3243 def reset(self):
3244 self.function = None
3245 self.state = self.state_dsl_start
3246 self.parameter_indent = None
3247 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003248 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003249 self.group = 0
3250 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003251 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003252 self.indent = IndentStack()
3253 self.kind = CALLABLE
3254 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003255 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003256 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003257
Larry Hastingsebdcb502013-11-23 14:54:00 -08003258 def directive_version(self, required):
3259 global version
3260 if version_comparitor(version, required) < 0:
3261 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3262
Larry Hastings31826802013-10-19 00:09:25 -07003263 def directive_module(self, name):
3264 fields = name.split('.')
3265 new = fields.pop()
3266 module, cls = self.clinic._module_and_class(fields)
3267 if cls:
3268 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003269
3270 if name in module.classes:
3271 fail("Already defined module " + repr(name) + "!")
3272
Larry Hastings31826802013-10-19 00:09:25 -07003273 m = Module(name, module)
3274 module.modules[name] = m
3275 self.block.signatures.append(m)
3276
Larry Hastingsc2047262014-01-25 20:43:29 -08003277 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003278 fields = name.split('.')
3279 in_classes = False
3280 parent = self
3281 name = fields.pop()
3282 so_far = []
3283 module, cls = self.clinic._module_and_class(fields)
3284
Larry Hastingsc2047262014-01-25 20:43:29 -08003285 parent = cls or module
3286 if name in parent.classes:
3287 fail("Already defined class " + repr(name) + "!")
3288
3289 c = Class(name, module, cls, typedef, type_object)
3290 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003291 self.block.signatures.append(c)
3292
Larry Hastingsbebf7352014-01-17 17:47:17 -08003293 def directive_set(self, name, value):
3294 if name not in ("line_prefix", "line_suffix"):
3295 fail("unknown variable", repr(name))
3296
3297 value = value.format_map({
3298 'block comment start': '/*',
3299 'block comment end': '*/',
3300 })
3301
3302 self.clinic.__dict__[name] = value
3303
3304 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003305 if command == 'new':
3306 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003307 return
3308
Zachary Ware071baa62014-01-21 23:07:12 -06003309 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003310 self.clinic.get_destination(name).clear()
3311 fail("unknown destination command", repr(command))
3312
3313
Larry Hastings0759f842015-04-03 13:09:02 -07003314 def directive_output(self, command_or_name, destination=''):
3315 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003316
Larry Hastings0759f842015-04-03 13:09:02 -07003317 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003318 preset = self.clinic.presets.get(destination)
3319 if not preset:
3320 fail("Unknown preset " + repr(destination) + "!")
3321 fd.update(preset)
3322 return
3323
Larry Hastings0759f842015-04-03 13:09:02 -07003324 if command_or_name == "push":
3325 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003326 return
3327
Larry Hastings0759f842015-04-03 13:09:02 -07003328 if command_or_name == "pop":
3329 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003330 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003331 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003332 fd.update(previous_fd)
3333 return
3334
3335 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003336 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003337 self.block.output.append(pprint.pformat(fd))
3338 self.block.output.append('\n')
3339 return
3340
3341 d = self.clinic.get_destination(destination)
3342
Larry Hastings0759f842015-04-03 13:09:02 -07003343 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003344 for name in list(fd):
3345 fd[name] = d
3346 return
3347
Larry Hastings0759f842015-04-03 13:09:02 -07003348 if command_or_name not in fd:
3349 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3350 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003351
3352 def directive_dump(self, name):
3353 self.block.output.append(self.clinic.get_destination(name).dump())
3354
3355 def directive_print(self, *args):
3356 self.block.output.append(' '.join(args))
3357 self.block.output.append('\n')
3358
3359 def directive_preserve(self):
3360 if self.preserve_output:
3361 fail("Can't have preserve twice in one block!")
3362 self.preserve_output = True
3363
Larry Hastings31826802013-10-19 00:09:25 -07003364 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003365 if self.kind is not CALLABLE:
3366 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003367 self.kind = CLASS_METHOD
3368
3369 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003370 if self.kind is not CALLABLE:
3371 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003372 self.kind = STATIC_METHOD
3373
3374 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003375 if self.coexist:
3376 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003377 self.coexist = True
3378
3379 def parse(self, block):
3380 self.reset()
3381 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003382 self.saved_output = self.block.output
3383 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003384 block_start = self.clinic.block_parser.line_number
3385 lines = block.input.split('\n')
3386 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3387 if '\t' in line:
3388 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3389 self.state(line)
3390
3391 self.next(self.state_terminal)
3392 self.state(None)
3393
Larry Hastingsbebf7352014-01-17 17:47:17 -08003394 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3395
3396 if self.preserve_output:
3397 if block.output:
3398 fail("'preserve' only works for blocks that don't produce any output!")
3399 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003400
3401 @staticmethod
3402 def ignore_line(line):
3403 # ignore comment-only lines
3404 if line.lstrip().startswith('#'):
3405 return True
3406
3407 # Ignore empty lines too
3408 # (but not in docstring sections!)
3409 if not line.strip():
3410 return True
3411
3412 return False
3413
3414 @staticmethod
3415 def calculate_indent(line):
3416 return len(line) - len(line.strip())
3417
3418 def next(self, state, line=None):
3419 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3420 self.state = state
3421 if line is not None:
3422 self.state(line)
3423
3424 def state_dsl_start(self, line):
3425 # self.block = self.ClinicOutputBlock(self)
3426 if self.ignore_line(line):
3427 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003428
3429 # is it a directive?
3430 fields = shlex.split(line)
3431 directive_name = fields[0]
3432 directive = self.directives.get(directive_name, None)
3433 if directive:
3434 try:
3435 directive(*fields[1:])
3436 except TypeError as e:
3437 fail(str(e))
3438 return
3439
Larry Hastings31826802013-10-19 00:09:25 -07003440 self.next(self.state_modulename_name, line)
3441
3442 def state_modulename_name(self, line):
3443 # looking for declaration, which establishes the leftmost column
3444 # line should be
3445 # modulename.fnname [as c_basename] [-> return annotation]
3446 # square brackets denote optional syntax.
3447 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003448 # alternatively:
3449 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3450 # clones the parameters and return converter from that
3451 # function. you can't modify them. you must enter a
3452 # new docstring.
3453 #
Larry Hastings31826802013-10-19 00:09:25 -07003454 # (but we might find a directive first!)
3455 #
3456 # this line is permitted to start with whitespace.
3457 # we'll call this number of spaces F (for "function").
3458
3459 if not line.strip():
3460 return
3461
3462 self.indent.infer(line)
3463
Larry Hastings4a714d42014-01-14 22:22:41 -08003464 # are we cloning?
3465 before, equals, existing = line.rpartition('=')
3466 if equals:
3467 full_name, _, c_basename = before.partition(' as ')
3468 full_name = full_name.strip()
3469 c_basename = c_basename.strip()
3470 existing = existing.strip()
3471 if (is_legal_py_identifier(full_name) and
3472 (not c_basename or is_legal_c_identifier(c_basename)) and
3473 is_legal_py_identifier(existing)):
3474 # we're cloning!
3475 fields = [x.strip() for x in existing.split('.')]
3476 function_name = fields.pop()
3477 module, cls = self.clinic._module_and_class(fields)
3478
3479 for existing_function in (cls or module).functions:
3480 if existing_function.name == function_name:
3481 break
3482 else:
3483 existing_function = None
3484 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003485 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003486 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003487 fail("Couldn't find existing function " + repr(existing) + "!")
3488
3489 fields = [x.strip() for x in full_name.split('.')]
3490 function_name = fields.pop()
3491 module, cls = self.clinic._module_and_class(fields)
3492
3493 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3494 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003495 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 -08003496
3497 self.block.signatures.append(self.function)
3498 (cls or module).functions.append(self.function)
3499 self.next(self.state_function_docstring)
3500 return
3501
Larry Hastings31826802013-10-19 00:09:25 -07003502 line, _, returns = line.partition('->')
3503
3504 full_name, _, c_basename = line.partition(' as ')
3505 full_name = full_name.strip()
3506 c_basename = c_basename.strip() or None
3507
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003508 if not is_legal_py_identifier(full_name):
3509 fail("Illegal function name: {}".format(full_name))
3510 if c_basename and not is_legal_c_identifier(c_basename):
3511 fail("Illegal C basename: {}".format(c_basename))
3512
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003513 return_converter = None
3514 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003515 ast_input = "def x() -> {}: pass".format(returns)
3516 module = None
3517 try:
3518 module = ast.parse(ast_input)
3519 except SyntaxError:
3520 pass
3521 if not module:
3522 fail("Badly-formed annotation for " + full_name + ": " + returns)
3523 try:
3524 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003525 if legacy:
3526 fail("Legacy converter {!r} not allowed as a return converter"
3527 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003528 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003529 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003530 return_converter = return_converters[name](**kwargs)
3531 except ValueError:
3532 fail("Badly-formed annotation for " + full_name + ": " + returns)
3533
3534 fields = [x.strip() for x in full_name.split('.')]
3535 function_name = fields.pop()
3536 module, cls = self.clinic._module_and_class(fields)
3537
Larry Hastings8666e652014-01-12 14:12:59 -08003538 fields = full_name.split('.')
3539 if fields[-1] == '__new__':
3540 if (self.kind != CLASS_METHOD) or (not cls):
3541 fail("__new__ must be a class method!")
3542 self.kind = METHOD_NEW
3543 elif fields[-1] == '__init__':
3544 if (self.kind != CALLABLE) or (not cls):
3545 fail("__init__ must be a normal method, not a class or static method!")
3546 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003547 if not return_converter:
3548 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003549 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003550 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003551
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003552 if not return_converter:
3553 return_converter = CReturnConverter()
3554
Larry Hastings31826802013-10-19 00:09:25 -07003555 if not module:
3556 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3557 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3558 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3559 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003560
3561 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003562 type, name = correct_name_for_self(self.function)
3563 kwargs = {}
3564 if cls and type == "PyObject *":
3565 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08003566 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003567 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3568 self.function.parameters[sc.name] = p_self
3569
Larry Hastings4a714d42014-01-14 22:22:41 -08003570 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003571 self.next(self.state_parameters_start)
3572
3573 # Now entering the parameters section. The rules, formally stated:
3574 #
3575 # * All lines must be indented with spaces only.
3576 # * The first line must be a parameter declaration.
3577 # * The first line must be indented.
3578 # * This first line establishes the indent for parameters.
3579 # * We'll call this number of spaces P (for "parameter").
3580 # * Thenceforth:
3581 # * Lines indented with P spaces specify a parameter.
3582 # * Lines indented with > P spaces are docstrings for the previous
3583 # parameter.
3584 # * We'll call this number of spaces D (for "docstring").
3585 # * All subsequent lines indented with >= D spaces are stored as
3586 # part of the per-parameter docstring.
3587 # * All lines will have the first D spaces of the indent stripped
3588 # before they are stored.
3589 # * It's illegal to have a line starting with a number of spaces X
3590 # such that P < X < D.
3591 # * A line with < P spaces is the first line of the function
3592 # docstring, which ends processing for parameters and per-parameter
3593 # docstrings.
3594 # * The first line of the function docstring must be at the same
3595 # indent as the function declaration.
3596 # * It's illegal to have any line in the parameters section starting
3597 # with X spaces such that F < X < P. (As before, F is the indent
3598 # of the function declaration.)
3599 #
Larry Hastings31826802013-10-19 00:09:25 -07003600 # Also, currently Argument Clinic places the following restrictions on groups:
3601 # * Each group must contain at least one parameter.
3602 # * Each group may contain at most one group, which must be the furthest
3603 # thing in the group from the required parameters. (The nested group
3604 # must be the first in the group when it's before the required
3605 # parameters, and the last thing in the group when after the required
3606 # parameters.)
3607 # * There may be at most one (top-level) group to the left or right of
3608 # the required parameters.
3609 # * You must specify a slash, and it must be after all parameters.
3610 # (In other words: either all parameters are positional-only,
3611 # or none are.)
3612 #
3613 # Said another way:
3614 # * Each group must contain at least one parameter.
3615 # * All left square brackets before the required parameters must be
3616 # consecutive. (You can't have a left square bracket followed
3617 # by a parameter, then another left square bracket. You can't
3618 # have a left square bracket, a parameter, a right square bracket,
3619 # and then a left square bracket.)
3620 # * All right square brackets after the required parameters must be
3621 # consecutive.
3622 #
3623 # These rules are enforced with a single state variable:
3624 # "parameter_state". (Previously the code was a miasma of ifs and
3625 # separate boolean state variables.) The states are:
3626 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003627 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
3628 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003629 #
3630 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3631 # 1: ps_left_square_before. left square brackets before required parameters.
3632 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003633 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3634 # (we don't know yet). (renumber left groups!)
3635 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3636 # now must have default values.
3637 # 5: ps_group_after. in a group, after required parameters.
3638 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07003639 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003640 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07003641
3642 def state_parameters_start(self, line):
3643 if self.ignore_line(line):
3644 return
3645
3646 # if this line is not indented, we have no parameters
3647 if not self.indent.infer(line):
3648 return self.next(self.state_function_docstring, line)
3649
Larry Hastings2a727912014-01-16 11:32:01 -08003650 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003651 return self.next(self.state_parameter, line)
3652
3653
3654 def to_required(self):
3655 """
3656 Transition to the "required" parameter state.
3657 """
3658 if self.parameter_state != self.ps_required:
3659 self.parameter_state = self.ps_required
3660 for p in self.function.parameters.values():
3661 p.group = -p.group
3662
3663 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003664 if self.parameter_continuation:
3665 line = self.parameter_continuation + ' ' + line.lstrip()
3666 self.parameter_continuation = ''
3667
Larry Hastings31826802013-10-19 00:09:25 -07003668 if self.ignore_line(line):
3669 return
3670
3671 assert self.indent.depth == 2
3672 indent = self.indent.infer(line)
3673 if indent == -1:
3674 # we outdented, must be to definition column
3675 return self.next(self.state_function_docstring, line)
3676
3677 if indent == 1:
3678 # we indented, must be to new parameter docstring column
3679 return self.next(self.state_parameter_docstring_start, line)
3680
Larry Hastings2a727912014-01-16 11:32:01 -08003681 line = line.rstrip()
3682 if line.endswith('\\'):
3683 self.parameter_continuation = line[:-1]
3684 return
3685
Larry Hastings31826802013-10-19 00:09:25 -07003686 line = line.lstrip()
3687
3688 if line in ('*', '/', '[', ']'):
3689 self.parse_special_symbol(line)
3690 return
3691
3692 if self.parameter_state in (self.ps_start, self.ps_required):
3693 self.to_required()
3694 elif self.parameter_state == self.ps_left_square_before:
3695 self.parameter_state = self.ps_group_before
3696 elif self.parameter_state == self.ps_group_before:
3697 if not self.group:
3698 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003699 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003700 pass
3701 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003702 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003703
Larry Hastings7726ac92014-01-31 22:03:12 -08003704 # handle "as" for parameters too
3705 c_name = None
3706 name, have_as_token, trailing = line.partition(' as ')
3707 if have_as_token:
3708 name = name.strip()
3709 if ' ' not in name:
3710 fields = trailing.strip().split(' ')
3711 if not fields:
3712 fail("Invalid 'as' clause!")
3713 c_name = fields[0]
3714 if c_name.endswith(':'):
3715 name += ':'
3716 c_name = c_name[:-1]
3717 fields[0] = name
3718 line = ' '.join(fields)
3719
Larry Hastings2a727912014-01-16 11:32:01 -08003720 base, equals, default = line.rpartition('=')
3721 if not equals:
3722 base = default
3723 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003724
Larry Hastings31826802013-10-19 00:09:25 -07003725 module = None
3726 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003727 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003728 module = ast.parse(ast_input)
3729 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003730 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003731 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003732 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08003733 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003734 default = None
3735 ast_input = "def x({}): pass".format(line)
3736 module = ast.parse(ast_input)
3737 except SyntaxError:
3738 pass
Larry Hastings31826802013-10-19 00:09:25 -07003739 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003740 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003741
3742 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003743
3744 if len(function_args.args) > 1:
3745 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
3746 if function_args.defaults or function_args.kw_defaults:
3747 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
3748 if function_args.vararg or function_args.kwarg:
3749 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
3750
Larry Hastings31826802013-10-19 00:09:25 -07003751 parameter = function_args.args[0]
3752
Larry Hastings16c51912014-01-07 11:53:01 -08003753 parameter_name = parameter.arg
3754 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3755
Larry Hastings2a727912014-01-16 11:32:01 -08003756 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003757 if self.parameter_state == self.ps_optional:
3758 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 -08003759 value = unspecified
3760 if 'py_default' in kwargs:
3761 fail("You can't specify py_default without specifying a default value!")
3762 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003763 if self.parameter_state == self.ps_required:
3764 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003765 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003766 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003767 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003768 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003769 try:
3770 module = ast.parse(ast_input)
3771
Larry Hastings5c661892014-01-24 06:17:25 -08003772 if 'c_default' not in kwargs:
3773 # we can only represent very simple data values in C.
3774 # detect whether default is okay, via a blacklist
3775 # of disallowed ast nodes.
3776 class DetectBadNodes(ast.NodeVisitor):
3777 bad = False
3778 def bad_node(self, node):
3779 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003780
Larry Hastings5c661892014-01-24 06:17:25 -08003781 # inline function call
3782 visit_Call = bad_node
3783 # inline if statement ("x = 3 if y else z")
3784 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003785
Larry Hastings5c661892014-01-24 06:17:25 -08003786 # comprehensions and generator expressions
3787 visit_ListComp = visit_SetComp = bad_node
3788 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003789
Larry Hastings5c661892014-01-24 06:17:25 -08003790 # literals for advanced types
3791 visit_Dict = visit_Set = bad_node
3792 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003793
Larry Hastings5c661892014-01-24 06:17:25 -08003794 # "starred": "a = [1, 2, 3]; *a"
3795 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003796
Larry Hastings5c661892014-01-24 06:17:25 -08003797 # allow ellipsis, for now
3798 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003799
Larry Hastings5c661892014-01-24 06:17:25 -08003800 blacklist = DetectBadNodes()
3801 blacklist.visit(module)
3802 bad = blacklist.bad
3803 else:
3804 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003805 # but at least make an attempt at ensuring it's a valid expression.
3806 try:
3807 value = eval(default)
3808 if value == unspecified:
3809 fail("'unspecified' is not a legal default value!")
3810 except NameError:
3811 pass # probably a named constant
3812 except Exception as e:
3813 fail("Malformed expression given as default value\n"
3814 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003815 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003816 fail("Unsupported expression as default value: " + repr(default))
3817
3818 expr = module.body[0].value
3819 # mild hack: explicitly support NULL as a default value
3820 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3821 value = NULL
3822 py_default = 'None'
3823 c_default = "NULL"
3824 elif (isinstance(expr, ast.BinOp) or
3825 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3826 c_default = kwargs.get("c_default")
3827 if not (isinstance(c_default, str) and c_default):
3828 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3829 py_default = default
3830 value = unknown
3831 elif isinstance(expr, ast.Attribute):
3832 a = []
3833 n = expr
3834 while isinstance(n, ast.Attribute):
3835 a.append(n.attr)
3836 n = n.value
3837 if not isinstance(n, ast.Name):
3838 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3839 a.append(n.id)
3840 py_default = ".".join(reversed(a))
3841
3842 c_default = kwargs.get("c_default")
3843 if not (isinstance(c_default, str) and c_default):
3844 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3845
3846 try:
3847 value = eval(py_default)
3848 except NameError:
3849 value = unknown
3850 else:
3851 value = ast.literal_eval(expr)
3852 py_default = repr(value)
3853 if isinstance(value, (bool, None.__class__)):
3854 c_default = "Py_" + py_default
3855 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003856 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003857 else:
3858 c_default = py_default
3859
3860 except SyntaxError as e:
3861 fail("Syntax error: " + repr(e.text))
3862 except (ValueError, AttributeError):
3863 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003864 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003865 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003866 if not (isinstance(c_default, str) and c_default):
3867 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3868
Larry Hastings2a727912014-01-16 11:32:01 -08003869 kwargs.setdefault('c_default', c_default)
3870 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003871
Larry Hastings31826802013-10-19 00:09:25 -07003872 dict = legacy_converters if legacy else converters
3873 legacy_str = "legacy " if legacy else ""
3874 if name not in dict:
3875 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08003876 # if you use a c_name for the parameter, we just give that name to the converter
3877 # but the parameter object gets the python name
3878 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07003879
3880 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003881
3882 if isinstance(converter, self_converter):
3883 if len(self.function.parameters) == 1:
3884 if (self.parameter_state != self.ps_required):
3885 fail("A 'self' parameter cannot be marked optional.")
3886 if value is not unspecified:
3887 fail("A 'self' parameter cannot have a default value.")
3888 if self.group:
3889 fail("A 'self' parameter cannot be in an optional group.")
3890 kind = inspect.Parameter.POSITIONAL_ONLY
3891 self.parameter_state = self.ps_start
3892 self.function.parameters.clear()
3893 else:
3894 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3895
Larry Hastings31826802013-10-19 00:09:25 -07003896 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003897
3898 if parameter_name in self.function.parameters:
3899 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003900 self.function.parameters[parameter_name] = p
3901
3902 def parse_converter(self, annotation):
3903 if isinstance(annotation, ast.Str):
3904 return annotation.s, True, {}
3905
3906 if isinstance(annotation, ast.Name):
3907 return annotation.id, False, {}
3908
Larry Hastings4a55fc52014-01-12 11:09:57 -08003909 if not isinstance(annotation, ast.Call):
3910 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003911
3912 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003913 symbols = globals()
3914
3915 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07003916 return name, False, kwargs
3917
3918 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07003919 if symbol == '*':
3920 if self.keyword_only:
3921 fail("Function " + self.function.name + " uses '*' more than once.")
3922 self.keyword_only = True
3923 elif symbol == '[':
3924 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3925 self.parameter_state = self.ps_left_square_before
3926 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3927 self.parameter_state = self.ps_group_after
3928 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003929 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003930 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08003931 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07003932 elif symbol == ']':
3933 if not self.group:
3934 fail("Function " + self.function.name + " has a ] without a matching [.")
3935 if not any(p.group == self.group for p in self.function.parameters.values()):
3936 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3937 self.group -= 1
3938 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3939 self.parameter_state = self.ps_group_before
3940 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3941 self.parameter_state = self.ps_right_square_after
3942 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003943 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003944 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003945 if self.positional_only:
3946 fail("Function " + self.function.name + " uses '/' more than once.")
3947 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08003948 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003949 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003950 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3951 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003952 if self.keyword_only:
3953 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03003954 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07003955 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08003956 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07003957 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3958 p.kind = inspect.Parameter.POSITIONAL_ONLY
3959
3960 def state_parameter_docstring_start(self, line):
3961 self.parameter_docstring_indent = len(self.indent.margin)
3962 assert self.indent.depth == 3
3963 return self.next(self.state_parameter_docstring, line)
3964
3965 # every line of the docstring must start with at least F spaces,
3966 # where F > P.
3967 # these F spaces will be stripped.
3968 def state_parameter_docstring(self, line):
3969 stripped = line.strip()
3970 if stripped.startswith('#'):
3971 return
3972
3973 indent = self.indent.measure(line)
3974 if indent < self.parameter_docstring_indent:
3975 self.indent.infer(line)
3976 assert self.indent.depth < 3
3977 if self.indent.depth == 2:
3978 # back to a parameter
3979 return self.next(self.state_parameter, line)
3980 assert self.indent.depth == 1
3981 return self.next(self.state_function_docstring, line)
3982
3983 assert self.function.parameters
3984 last_parameter = next(reversed(list(self.function.parameters.values())))
3985
3986 new_docstring = last_parameter.docstring
3987
3988 if new_docstring:
3989 new_docstring += '\n'
3990 if stripped:
3991 new_docstring += self.indent.dedent(line)
3992
3993 last_parameter.docstring = new_docstring
3994
3995 # the final stanza of the DSL is the docstring.
3996 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003997 if self.group:
3998 fail("Function " + self.function.name + " has a ] without a matching [.")
3999
4000 stripped = line.strip()
4001 if stripped.startswith('#'):
4002 return
4003
4004 new_docstring = self.function.docstring
4005 if new_docstring:
4006 new_docstring += "\n"
4007 if stripped:
4008 line = self.indent.dedent(line).rstrip()
4009 else:
4010 line = ''
4011 new_docstring += line
4012 self.function.docstring = new_docstring
4013
4014 def format_docstring(self):
4015 f = self.function
4016
Larry Hastings5c661892014-01-24 06:17:25 -08004017 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
4018 if new_or_init and not f.docstring:
4019 # don't render a docstring at all, no signature, nothing.
4020 return f.docstring
4021
Larry Hastings2623c8c2014-02-08 22:15:29 -08004022 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08004023 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07004024
4025 ##
4026 ## docstring first line
4027 ##
4028
Larry Hastings2623c8c2014-02-08 22:15:29 -08004029 if new_or_init:
4030 # classes get *just* the name of the class
4031 # not __new__, not __init__, and not module.classname
4032 assert f.cls
4033 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004034 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004035 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004036 add('(')
4037
4038 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004039 assert parameters, "We should always have a self parameter. " + repr(f)
4040 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004041 # self is always positional-only.
4042 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004043 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004044 positional_only = True
4045 for p in parameters[1:]:
4046 if not p.is_positional_only():
4047 positional_only = False
4048 else:
4049 assert positional_only
4050 if positional_only:
4051 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004052 else:
4053 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004054 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004055
4056 right_bracket_count = 0
4057
4058 def fix_right_bracket_count(desired):
4059 nonlocal right_bracket_count
4060 s = ''
4061 while right_bracket_count < desired:
4062 s += '['
4063 right_bracket_count += 1
4064 while right_bracket_count > desired:
4065 s += ']'
4066 right_bracket_count -= 1
4067 return s
4068
Larry Hastings2623c8c2014-02-08 22:15:29 -08004069 need_slash = False
4070 added_slash = False
4071 need_a_trailing_slash = False
4072
4073 # we only need a trailing slash:
4074 # * if this is not a "docstring_only" signature
4075 # * and if the last *shown* parameter is
4076 # positional only
4077 if not f.docstring_only:
4078 for p in reversed(parameters):
4079 if not p.converter.show_in_signature:
4080 continue
4081 if p.is_positional_only():
4082 need_a_trailing_slash = True
4083 break
4084
4085
Larry Hastings31826802013-10-19 00:09:25 -07004086 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004087
4088 first_parameter = True
4089 last_p = parameters[-1]
4090 line_length = len(''.join(text))
4091 indent = " " * line_length
4092 def add_parameter(text):
4093 nonlocal line_length
4094 nonlocal first_parameter
4095 if first_parameter:
4096 s = text
4097 first_parameter = False
4098 else:
4099 s = ' ' + text
4100 if line_length + len(s) >= 72:
4101 add('\n')
4102 add(indent)
4103 line_length = len(indent)
4104 s = text
4105 line_length += len(s)
4106 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004107
4108 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004109 if not p.converter.show_in_signature:
4110 continue
Larry Hastings31826802013-10-19 00:09:25 -07004111 assert p.name
4112
Larry Hastings2623c8c2014-02-08 22:15:29 -08004113 is_self = isinstance(p.converter, self_converter)
4114 if is_self and f.docstring_only:
4115 # this isn't a real machine-parsable signature,
4116 # so let's not print the "self" parameter
4117 continue
4118
4119 if p.is_positional_only():
4120 need_slash = not f.docstring_only
4121 elif need_slash and not (added_slash or p.is_positional_only()):
4122 added_slash = True
4123 add_parameter('/,')
4124
Larry Hastings31826802013-10-19 00:09:25 -07004125 if p.is_keyword_only() and not added_star:
4126 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004127 add_parameter('*,')
4128
4129 p_add, p_output = text_accumulator()
4130 p_add(fix_right_bracket_count(p.right_bracket_count))
4131
4132 if isinstance(p.converter, self_converter):
4133 # annotate first parameter as being a "self".
4134 #
4135 # if inspect.Signature gets this function,
4136 # and it's already bound, the self parameter
4137 # will be stripped off.
4138 #
4139 # if it's not bound, it should be marked
4140 # as positional-only.
4141 #
4142 # note: we don't print "self" for __init__,
4143 # because this isn't actually the signature
4144 # for __init__. (it can't be, __init__ doesn't
4145 # have a docstring.) if this is an __init__
4146 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004147 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004148 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004149
Larry Hastings5c661892014-01-24 06:17:25 -08004150 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004151 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004152
Larry Hastings31826802013-10-19 00:09:25 -07004153 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004154 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004155 value = p.converter.py_default
4156 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004157 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004158 p_add(value)
4159
4160 if (p != last_p) or need_a_trailing_slash:
4161 p_add(',')
4162
4163 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004164
4165 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004166 if need_a_trailing_slash:
4167 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004168 add(')')
4169
Larry Hastings2a727912014-01-16 11:32:01 -08004170 # PEP 8 says:
4171 #
4172 # The Python standard library will not use function annotations
4173 # as that would result in a premature commitment to a particular
4174 # annotation style. Instead, the annotations are left for users
4175 # to discover and experiment with useful annotation styles.
4176 #
4177 # therefore this is commented out:
4178 #
4179 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004180 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004181 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004182
Larry Hastings2623c8c2014-02-08 22:15:29 -08004183 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004184 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004185
Larry Hastings31826802013-10-19 00:09:25 -07004186 docstring_first_line = output()
4187
4188 # now fix up the places where the brackets look wrong
4189 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4190
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004191 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004192 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004193 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004194 for p in parameters:
4195 if not p.docstring.strip():
4196 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004197 if spacer_line:
4198 add('\n')
4199 else:
4200 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004201 add(" ")
4202 add(p.name)
4203 add('\n')
4204 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004205 parameters = output()
4206 if parameters:
4207 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004208
4209 ##
4210 ## docstring body
4211 ##
4212
4213 docstring = f.docstring.rstrip()
4214 lines = [line.rstrip() for line in docstring.split('\n')]
4215
4216 # Enforce the summary line!
4217 # The first line of a docstring should be a summary of the function.
4218 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4219 # by itself.
4220 #
4221 # Argument Clinic enforces the following rule:
4222 # * either the docstring is empty,
4223 # * or it must have a summary line.
4224 #
4225 # Guido said Clinic should enforce this:
4226 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4227
4228 if len(lines) >= 2:
4229 if lines[1]:
4230 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4231 "Every non-blank function docstring must start with\n" +
4232 "a single line summary followed by an empty line.")
4233 elif len(lines) == 1:
4234 # the docstring is only one line right now--the summary line.
4235 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004236 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004237 lines.append('')
4238
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004239 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4240 if parameters_marker_count > 1:
4241 fail('You may not specify {parameters} more than once in a docstring!')
4242
4243 if not parameters_marker_count:
4244 # insert after summary line
4245 lines.insert(2, '{parameters}')
4246
4247 # insert at front of docstring
4248 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004249
4250 docstring = "\n".join(lines)
4251
4252 add(docstring)
4253 docstring = output()
4254
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004255 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004256 docstring = docstring.rstrip()
4257
4258 return docstring
4259
4260 def state_terminal(self, line):
4261 """
4262 Called when processing the block is done.
4263 """
4264 assert not line
4265
4266 if not self.function:
4267 return
4268
4269 if self.keyword_only:
4270 values = self.function.parameters.values()
4271 if not values:
4272 no_parameter_after_star = True
4273 else:
4274 last_parameter = next(reversed(list(values)))
4275 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4276 if no_parameter_after_star:
4277 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4278
4279 # remove trailing whitespace from all parameter docstrings
4280 for name, value in self.function.parameters.items():
4281 if not value:
4282 continue
4283 value.docstring = value.docstring.rstrip()
4284
4285 self.function.docstring = self.format_docstring()
4286
4287
Larry Hastings5c661892014-01-24 06:17:25 -08004288
4289
Larry Hastings31826802013-10-19 00:09:25 -07004290# maps strings to callables.
4291# the callable should return an object
4292# that implements the clinic parser
4293# interface (__init__ and parse).
4294#
4295# example parsers:
4296# "clinic", handles the Clinic DSL
4297# "python", handles running Python code
4298#
4299parsers = {'clinic' : DSLParser, 'python': PythonParser}
4300
4301
4302clinic = None
4303
4304
4305def main(argv):
4306 import sys
4307
4308 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4309 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4310
4311 import argparse
4312 cmdline = argparse.ArgumentParser()
4313 cmdline.add_argument("-f", "--force", action='store_true')
4314 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004315 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004316 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004317 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004318 cmdline.add_argument("filename", type=str, nargs="*")
4319 ns = cmdline.parse_args(argv)
4320
4321 if ns.converters:
4322 if ns.filename:
4323 print("Usage error: can't specify --converters and a filename at the same time.")
4324 print()
4325 cmdline.print_usage()
4326 sys.exit(-1)
4327 converters = []
4328 return_converters = []
4329 ignored = set("""
4330 add_c_converter
4331 add_c_return_converter
4332 add_default_legacy_c_converter
4333 add_legacy_c_converter
4334 """.strip().split())
4335 module = globals()
4336 for name in module:
4337 for suffix, ids in (
4338 ("_return_converter", return_converters),
4339 ("_converter", converters),
4340 ):
4341 if name in ignored:
4342 continue
4343 if name.endswith(suffix):
4344 ids.append((name, name[:-len(suffix)]))
4345 break
4346 print()
4347
4348 print("Legacy converters:")
4349 legacy = sorted(legacy_converters)
4350 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4351 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4352 print()
4353
4354 for title, attribute, ids in (
4355 ("Converters", 'converter_init', converters),
4356 ("Return converters", 'return_converter_init', return_converters),
4357 ):
4358 print(title + ":")
4359 longest = -1
4360 for name, short_name in ids:
4361 longest = max(longest, len(short_name))
4362 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4363 cls = module[name]
4364 callable = getattr(cls, attribute, None)
4365 if not callable:
4366 continue
4367 signature = inspect.signature(callable)
4368 parameters = []
4369 for parameter_name, parameter in signature.parameters.items():
4370 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4371 if parameter.default != inspect.Parameter.empty:
4372 s = '{}={!r}'.format(parameter_name, parameter.default)
4373 else:
4374 s = parameter_name
4375 parameters.append(s)
4376 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004377 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004378 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4379 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004380 sys.exit(0)
4381
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004382 if ns.make:
4383 if ns.output or ns.filename:
4384 print("Usage error: can't use -o or filenames with --make.")
4385 print()
4386 cmdline.print_usage()
4387 sys.exit(-1)
4388 for root, dirs, files in os.walk('.'):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004389 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004390 if rcs_dir in dirs:
4391 dirs.remove(rcs_dir)
4392 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004393 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004394 continue
4395 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004396 if ns.verbose:
4397 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004398 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004399 return
4400
Larry Hastings31826802013-10-19 00:09:25 -07004401 if not ns.filename:
4402 cmdline.print_usage()
4403 sys.exit(-1)
4404
4405 if ns.output and len(ns.filename) > 1:
4406 print("Usage error: can't use -o with multiple filenames.")
4407 print()
4408 cmdline.print_usage()
4409 sys.exit(-1)
4410
4411 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004412 if ns.verbose:
4413 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004414 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004415
4416
4417if __name__ == "__main__":
4418 sys.exit(main(sys.argv[1:]))