blob: 75ac673737edbb48fc24004a2a244f502fe62333 [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
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700708 parser_prototype_fastcall = normalize_snippet("""
709 static PyObject *
710 {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
711 """)
712
Larry Hastings7726ac92014-01-31 22:03:12 -0800713 parser_prototype_varargs = normalize_snippet("""
714 static PyObject *
715 {c_basename}({self_type}{self_name}, PyObject *args)
716 """)
717
718 # 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
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800828 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800829 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700830
Larry Hastings7726ac92014-01-31 22:03:12 -0800831 parser_definition = parser_body(parser_prototype, normalize_snippet("""
832 if (!PyArg_UnpackTuple(args, "{name}",
833 {unpack_min}, {unpack_max},
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300834 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800835 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300836 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800837 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800838
839 elif positional:
840 # positional-only, but no option groups
841 # we only need one call to PyArg_ParseTuple
842
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800843 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800844 parser_prototype = parser_prototype_varargs
Larry Hastingsbebf7352014-01-17 17:47:17 -0800845
Larry Hastings7726ac92014-01-31 22:03:12 -0800846 parser_definition = parser_body(parser_prototype, normalize_snippet("""
Serhiy Storchaka247789c2015-04-24 00:40:51 +0300847 if (!PyArg_ParseTuple(args, "{format_units}:{name}",
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300848 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800849 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300850 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800851 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800852
Victor Stinnerf0ccbbb2016-09-09 17:40:38 -0700853 elif not new_or_init:
854 flags = "METH_FASTCALL"
855
856 parser_prototype = parser_prototype_fastcall
857
858 body = normalize_snippet("""
859 if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
860 {parse_arguments})) {{
861 goto exit;
862 }}
863 """, indent=4)
864 parser_definition = parser_body(parser_prototype, body)
865 parser_definition = insert_keywords(parser_definition)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800866 else:
867 # positional-or-keyword arguments
868 flags = "METH_VARARGS|METH_KEYWORDS"
869
Larry Hastings7726ac92014-01-31 22:03:12 -0800870 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800871
Larry Hastings7726ac92014-01-31 22:03:12 -0800872 body = normalize_snippet("""
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300873 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300874 {parse_arguments})) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800875 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300876 }}
877 """, indent=4)
Serhiy Storchaka9171a8b2016-08-14 10:52:18 +0300878 parser_definition = parser_body(parser_prototype, body)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800879 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700880
Larry Hastings31826802013-10-19 00:09:25 -0700881
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800882 if new_or_init:
883 methoddef_define = ''
884
885 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800886 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800887 else:
888 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800889 parser_prototype = normalize_snippet("""
890 static int
891 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
892 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800893
894 fields = list(parser_body_fields)
895 parses_positional = 'METH_NOARGS' not in flags
896 parses_keywords = 'METH_KEYWORDS' in flags
897 if parses_keywords:
898 assert parses_positional
899
900 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800901 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300902 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800903 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300904 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800905 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800906 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800907 fields.insert(0, normalize_snippet("""
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300908 if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
Larry Hastings7726ac92014-01-31 22:03:12 -0800909 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +0300910 }}
Larry Hastings7726ac92014-01-31 22:03:12 -0800911 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800912
913 parser_definition = parser_body(parser_prototype, *fields)
914 if parses_keywords:
915 parser_definition = insert_keywords(parser_definition)
916
Larry Hastings31826802013-10-19 00:09:25 -0700917
Larry Hastingsbebf7352014-01-17 17:47:17 -0800918 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800919 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700920
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800921 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700922
Larry Hastings7726ac92014-01-31 22:03:12 -0800923 methoddef_ifndef = ''
924 conditional = self.cpp.condition()
925 if not conditional:
926 cpp_if = cpp_endif = ''
927 else:
928 cpp_if = "#if " + conditional
929 cpp_endif = "#endif /* " + conditional + " */"
930
Larry Hastings0759f842015-04-03 13:09:02 -0700931 if methoddef_define and f.name not in clinic.ifndef_symbols:
932 clinic.ifndef_symbols.add(f.name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800933 methoddef_ifndef = normalize_snippet("""
934 #ifndef {methoddef_name}
935 #define {methoddef_name}
936 #endif /* !defined({methoddef_name}) */
937 """)
938
939
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800940 # add ';' to the end of parser_prototype and impl_prototype
941 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800942 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800943 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800944 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800945 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700946
Larry Hastingsbebf7352014-01-17 17:47:17 -0800947 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800948 impl_prototype = impl_definition
949 if impl_prototype:
950 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700951
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800952 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800953
954 d = {
955 "docstring_prototype" : docstring_prototype,
956 "docstring_definition" : docstring_definition,
957 "impl_prototype" : impl_prototype,
958 "methoddef_define" : methoddef_define,
959 "parser_prototype" : parser_prototype,
960 "parser_definition" : parser_definition,
961 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800962 "cpp_if" : cpp_if,
963 "cpp_endif" : cpp_endif,
964 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800965 }
966
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800967 # make sure we didn't forget to assign something,
968 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -0800969 d2 = {}
970 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800971 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800972 if value:
973 value = '\n' + value + '\n'
974 d2[name] = value
975 return d2
Larry Hastings31826802013-10-19 00:09:25 -0700976
977 @staticmethod
978 def group_to_variable_name(group):
979 adjective = "left_" if group < 0 else "right_"
980 return "group_" + adjective + str(abs(group))
981
982 def render_option_group_parsing(self, f, template_dict):
983 # positional only, grouped, optional arguments!
984 # can be optional on the left or right.
985 # here's an example:
986 #
987 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
988 #
989 # Here group D are required, and all other groups are optional.
990 # (Group D's "group" is actually None.)
991 # We can figure out which sets of arguments we have based on
992 # how many arguments are in the tuple.
993 #
994 # Note that you need to count up on both sides. For example,
995 # you could have groups C+D, or C+D+E, or C+D+E+F.
996 #
997 # What if the number of arguments leads us to an ambiguous result?
998 # Clinic prefers groups on the left. So in the above example,
999 # five arguments would map to B+C, not C+D.
1000
1001 add, output = text_accumulator()
1002 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001003 if isinstance(parameters[0].converter, self_converter):
1004 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -07001005
1006 groups = []
1007 group = None
1008 left = []
1009 right = []
1010 required = []
1011 last = unspecified
1012
1013 for p in parameters:
1014 group_id = p.group
1015 if group_id != last:
1016 last = group_id
1017 group = []
1018 if group_id < 0:
1019 left.append(group)
1020 elif group_id == 0:
1021 group = required
1022 else:
1023 right.append(group)
1024 group.append(p)
1025
1026 count_min = sys.maxsize
1027 count_max = -1
1028
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001029 add("switch (PyTuple_GET_SIZE(args)) {\n")
Larry Hastings31826802013-10-19 00:09:25 -07001030 for subset in permute_optional_groups(left, required, right):
1031 count = len(subset)
1032 count_min = min(count_min, count)
1033 count_max = max(count_max, count)
1034
Larry Hastings583baa82014-01-12 08:49:30 -08001035 if count == 0:
1036 add(""" case 0:
1037 break;
1038""")
1039 continue
1040
Larry Hastings31826802013-10-19 00:09:25 -07001041 group_ids = {p.group for p in subset} # eliminate duplicates
1042 d = {}
1043 d['count'] = count
1044 d['name'] = f.name
Larry Hastings31826802013-10-19 00:09:25 -07001045 d['format_units'] = "".join(p.converter.format_unit for p in subset)
1046
1047 parse_arguments = []
1048 for p in subset:
1049 p.converter.parse_argument(parse_arguments)
1050 d['parse_arguments'] = ", ".join(parse_arguments)
1051
1052 group_ids.discard(0)
1053 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
1054 lines = "\n".join(lines)
1055
1056 s = """
1057 case {count}:
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001058 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
Larry Hastings46258262014-01-22 03:05:49 -08001059 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03001060 }}
Larry Hastings31826802013-10-19 00:09:25 -07001061 {group_booleans}
1062 break;
1063"""[1:]
1064 s = linear_format(s, group_booleans=lines)
1065 s = s.format_map(d)
1066 add(s)
1067
1068 add(" default:\n")
1069 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
1070 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -08001071 add(' goto exit;\n')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001072 add("}")
1073 template_dict['option_group_parsing'] = format_escape(output())
Larry Hastings31826802013-10-19 00:09:25 -07001074
Larry Hastingsbebf7352014-01-17 17:47:17 -08001075 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001076 if not f:
1077 return ""
1078
1079 add, output = text_accumulator()
1080 data = CRenderData()
1081
Larry Hastings7726ac92014-01-31 22:03:12 -08001082 assert f.parameters, "We should always have a 'self' at this point!"
1083 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07001084 converters = [p.converter for p in parameters]
1085
Larry Hastings5c661892014-01-24 06:17:25 -08001086 templates = self.output_templates(f)
1087
1088 f_self = parameters[0]
1089 selfless = parameters[1:]
1090 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1091
1092 last_group = 0
1093 first_optional = len(selfless)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03001094 positional = selfless and selfless[-1].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08001095 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1096 default_return_converter = (not f.return_converter or
1097 f.return_converter.type == 'PyObject *')
1098 has_option_groups = False
1099
1100 # offset i by -1 because first_optional needs to ignore self
1101 for i, p in enumerate(parameters, -1):
1102 c = p.converter
1103
1104 if (i != -1) and (p.default is not unspecified):
1105 first_optional = min(first_optional, i)
1106
1107 # insert group variable
1108 group = p.group
1109 if last_group != group:
1110 last_group = group
1111 if group:
1112 group_name = self.group_to_variable_name(group)
1113 data.impl_arguments.append(group_name)
1114 data.declarations.append("int " + group_name + " = 0;")
1115 data.impl_parameters.append("int " + group_name)
1116 has_option_groups = True
1117
1118 c.render(p, data)
1119
1120 if has_option_groups and (not positional):
1121 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1122
1123 # HACK
1124 # when we're METH_O, but have a custom return converter,
1125 # we use "impl_parameters" for the parsing function
1126 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001127 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001128 # as variables in the parsing function. but since it's
1129 # METH_O, we have exactly one anyway, so we know exactly
1130 # where it is.
1131 if ("METH_O" in templates['methoddef_define'] and
Serhiy Storchaka92e8af62015-04-04 00:12:11 +03001132 '{impl_parameters}' in templates['parser_prototype']):
Larry Hastings5c661892014-01-24 06:17:25 -08001133 data.declarations.pop(0)
1134
Larry Hastings31826802013-10-19 00:09:25 -07001135 template_dict = {}
1136
1137 full_name = f.full_name
1138 template_dict['full_name'] = full_name
1139
Larry Hastings5c661892014-01-24 06:17:25 -08001140 if new_or_init:
1141 name = f.cls.name
1142 else:
1143 name = f.name
1144
Larry Hastings31826802013-10-19 00:09:25 -07001145 template_dict['name'] = name
1146
Larry Hastings8666e652014-01-12 14:12:59 -08001147 if f.c_basename:
1148 c_basename = f.c_basename
1149 else:
1150 fields = full_name.split(".")
1151 if fields[-1] == '__new__':
1152 fields.pop()
1153 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001154
Larry Hastings31826802013-10-19 00:09:25 -07001155 template_dict['c_basename'] = c_basename
1156
1157 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1158 template_dict['methoddef_name'] = methoddef_name
1159
1160 template_dict['docstring'] = self.docstring_for_c_string(f)
1161
Larry Hastingsc2047262014-01-25 20:43:29 -08001162 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001163 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001164
Larry Hastings31826802013-10-19 00:09:25 -07001165 f.return_converter.render(f, data)
1166 template_dict['impl_return_type'] = f.return_converter.type
1167
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001168 template_dict['declarations'] = format_escape("\n".join(data.declarations))
Larry Hastings31826802013-10-19 00:09:25 -07001169 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001170 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001171 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1172 template_dict['format_units'] = ''.join(data.format_units)
1173 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1174 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1175 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03001176 template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
1177 template_dict['cleanup'] = format_escape("".join(data.cleanup))
Larry Hastings31826802013-10-19 00:09:25 -07001178 template_dict['return_value'] = data.return_value
1179
Larry Hastings5c661892014-01-24 06:17:25 -08001180 # used by unpack tuple code generator
1181 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1182 unpack_min = first_optional
1183 unpack_max = len(selfless)
1184 template_dict['unpack_min'] = str(unpack_min)
1185 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001186
Larry Hastingsbebf7352014-01-17 17:47:17 -08001187 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001188 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001189
Larry Hastings0759f842015-04-03 13:09:02 -07001190 # buffers, not destination
1191 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001192 template = templates[name]
1193 if has_option_groups:
1194 template = linear_format(template,
1195 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001196 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001197 declarations=template_dict['declarations'],
1198 return_conversion=template_dict['return_conversion'],
1199 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001200 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001201 cleanup=template_dict['cleanup'],
1202 )
Larry Hastings31826802013-10-19 00:09:25 -07001203
Larry Hastingsbebf7352014-01-17 17:47:17 -08001204 # Only generate the "exit:" label
1205 # if we have any gotos
1206 need_exit_label = "goto exit;" in template
1207 template = linear_format(template,
1208 exit_label="exit:" if need_exit_label else ''
1209 )
Larry Hastings31826802013-10-19 00:09:25 -07001210
Larry Hastingsbebf7352014-01-17 17:47:17 -08001211 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001212
Larry Hastings89964c42015-04-14 18:07:59 -04001213 # mild hack:
1214 # reflow long impl declarations
1215 if name in {"impl_prototype", "impl_definition"}:
1216 s = wrap_declarations(s)
1217
Larry Hastingsbebf7352014-01-17 17:47:17 -08001218 if clinic.line_prefix:
1219 s = indent_all_lines(s, clinic.line_prefix)
1220 if clinic.line_suffix:
1221 s = suffix_all_lines(s, clinic.line_suffix)
1222
1223 destination.append(s)
1224
1225 return clinic.get_destination('block').dump()
1226
Larry Hastings31826802013-10-19 00:09:25 -07001227
1228
Larry Hastings5c661892014-01-24 06:17:25 -08001229
Larry Hastings31826802013-10-19 00:09:25 -07001230@contextlib.contextmanager
1231def OverrideStdioWith(stdout):
1232 saved_stdout = sys.stdout
1233 sys.stdout = stdout
1234 try:
1235 yield
1236 finally:
1237 assert sys.stdout is stdout
1238 sys.stdout = saved_stdout
1239
1240
Larry Hastings2623c8c2014-02-08 22:15:29 -08001241def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001242 """Create an re object for matching marker lines."""
R David Murray44b548d2016-09-08 13:59:53 -04001243 group_re = r"\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001244 pattern = r'{}({}){}'
1245 if whole_line:
1246 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001247 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1248 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001249
1250
1251class Block:
1252 r"""
1253 Represents a single block of text embedded in
1254 another file. If dsl_name is None, the block represents
1255 verbatim text, raw original text from the file, in
1256 which case "input" will be the only non-false member.
1257 If dsl_name is not None, the block represents a Clinic
1258 block.
1259
1260 input is always str, with embedded \n characters.
1261 input represents the original text from the file;
1262 if it's a Clinic block, it is the original text with
1263 the body_prefix and redundant leading whitespace removed.
1264
1265 dsl_name is either str or None. If str, it's the text
1266 found on the start line of the block between the square
1267 brackets.
1268
1269 signatures is either list or None. If it's a list,
1270 it may only contain clinic.Module, clinic.Class, and
1271 clinic.Function objects. At the moment it should
1272 contain at most one of each.
1273
1274 output is either str or None. If str, it's the output
1275 from this block, with embedded '\n' characters.
1276
1277 indent is either str or None. It's the leading whitespace
1278 that was found on every line of input. (If body_prefix is
1279 not empty, this is the indent *after* removing the
1280 body_prefix.)
1281
1282 preindent is either str or None. It's the whitespace that
1283 was found in front of every line of input *before* the
1284 "body_prefix" (see the Language object). If body_prefix
1285 is empty, preindent must always be empty too.
1286
1287 To illustrate indent and preindent: Assume that '_'
1288 represents whitespace. If the block processed was in a
1289 Python file, and looked like this:
1290 ____#/*[python]
1291 ____#__for a in range(20):
1292 ____#____print(a)
1293 ____#[python]*/
1294 "preindent" would be "____" and "indent" would be "__".
1295
1296 """
1297 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1298 assert isinstance(input, str)
1299 self.input = input
1300 self.dsl_name = dsl_name
1301 self.signatures = signatures or []
1302 self.output = output
1303 self.indent = indent
1304 self.preindent = preindent
1305
Larry Hastings581ee362014-01-28 05:00:08 -08001306 def __repr__(self):
1307 dsl_name = self.dsl_name or "text"
1308 def summarize(s):
1309 s = repr(s)
1310 if len(s) > 30:
1311 return s[:26] + "..." + s[0]
1312 return s
1313 return "".join((
1314 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1315
Larry Hastings31826802013-10-19 00:09:25 -07001316
1317class BlockParser:
1318 """
1319 Block-oriented parser for Argument Clinic.
1320 Iterator, yields Block objects.
1321 """
1322
1323 def __init__(self, input, language, *, verify=True):
1324 """
1325 "input" should be a str object
1326 with embedded \n characters.
1327
1328 "language" should be a Language object.
1329 """
1330 language.validate()
1331
1332 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1333 self.block_start_line_number = self.line_number = 0
1334
1335 self.language = language
1336 before, _, after = language.start_line.partition('{dsl_name}')
1337 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001338 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001339 self.start_re = create_regex(before, after)
1340 self.verify = verify
1341 self.last_checksum_re = None
1342 self.last_dsl_name = None
1343 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001344 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001345
1346 def __iter__(self):
1347 return self
1348
1349 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001350 while True:
1351 if not self.input:
1352 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001353
Larry Hastingsbebf7352014-01-17 17:47:17 -08001354 if self.dsl_name:
1355 return_value = self.parse_clinic_block(self.dsl_name)
1356 self.dsl_name = None
1357 self.first_block = False
1358 return return_value
1359 block = self.parse_verbatim_block()
1360 if self.first_block and not block.input:
1361 continue
1362 self.first_block = False
1363 return block
1364
Larry Hastings31826802013-10-19 00:09:25 -07001365
1366 def is_start_line(self, line):
1367 match = self.start_re.match(line.lstrip())
1368 return match.group(1) if match else None
1369
Larry Hastingse1b82532014-07-27 16:22:20 +02001370 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001371 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001372 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001373 if not lookahead:
1374 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001375 return line
Larry Hastings31826802013-10-19 00:09:25 -07001376
1377 def parse_verbatim_block(self):
1378 add, output = text_accumulator()
1379 self.block_start_line_number = self.line_number
1380
1381 while self.input:
1382 line = self._line()
1383 dsl_name = self.is_start_line(line)
1384 if dsl_name:
1385 self.dsl_name = dsl_name
1386 break
1387 add(line)
1388
1389 return Block(output())
1390
1391 def parse_clinic_block(self, dsl_name):
1392 input_add, input_output = text_accumulator()
1393 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001394 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001395 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1396
Larry Hastings90261132014-01-07 12:21:08 -08001397 def is_stop_line(line):
1398 # make sure to recognize stop line even if it
1399 # doesn't end with EOL (it could be the very end of the file)
1400 if not line.startswith(stop_line):
1401 return False
1402 remainder = line[len(stop_line):]
1403 return (not remainder) or remainder.isspace()
1404
Larry Hastings31826802013-10-19 00:09:25 -07001405 # consume body of program
1406 while self.input:
1407 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001408 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001409 break
1410 if body_prefix:
1411 line = line.lstrip()
1412 assert line.startswith(body_prefix)
1413 line = line[len(body_prefix):]
1414 input_add(line)
1415
1416 # consume output and checksum line, if present.
1417 if self.last_dsl_name == dsl_name:
1418 checksum_re = self.last_checksum_re
1419 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001420 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1421 assert _ == '{arguments}'
1422 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001423 self.last_dsl_name = dsl_name
1424 self.last_checksum_re = checksum_re
1425
1426 # scan forward for checksum line
1427 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001428 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001429 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001430 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001431 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001432 arguments = match.group(1) if match else None
1433 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001434 break
1435 output_add(line)
1436 if self.is_start_line(line):
1437 break
1438
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001439 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001440 if arguments:
1441 d = {}
1442 for field in shlex.split(arguments):
1443 name, equals, value = field.partition('=')
1444 if not equals:
1445 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1446 d[name.strip()] = value.strip()
1447
Larry Hastings31826802013-10-19 00:09:25 -07001448 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001449 if 'input' in d:
1450 checksum = d['output']
1451 input_checksum = d['input']
1452 else:
1453 checksum = d['checksum']
1454 input_checksum = None
1455
1456 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001457 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001458 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1459 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001460 "the end marker,\n"
1461 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001462 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001463 else:
1464 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001465 output_lines = output.splitlines(keepends=True)
1466 self.line_number -= len(output_lines)
1467 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001468 output = None
1469
1470 return Block(input_output(), dsl_name, output=output)
1471
1472
1473class BlockPrinter:
1474
1475 def __init__(self, language, f=None):
1476 self.language = language
1477 self.f = f or io.StringIO()
1478
1479 def print_block(self, block):
1480 input = block.input
1481 output = block.output
1482 dsl_name = block.dsl_name
1483 write = self.f.write
1484
Larry Hastings31826802013-10-19 00:09:25 -07001485 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1486
1487 if not dsl_name:
1488 write(input)
1489 return
1490
1491 write(self.language.start_line.format(dsl_name=dsl_name))
1492 write("\n")
1493
1494 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1495 if not body_prefix:
1496 write(input)
1497 else:
1498 for line in input.split('\n'):
1499 write(body_prefix)
1500 write(line)
1501 write("\n")
1502
1503 write(self.language.stop_line.format(dsl_name=dsl_name))
1504 write("\n")
1505
Larry Hastings581ee362014-01-28 05:00:08 -08001506 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001507 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001508 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001509 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001510 output += '\n'
1511 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001512
Larry Hastings581ee362014-01-28 05:00:08 -08001513 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1514 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001515 write("\n")
1516
Larry Hastingsbebf7352014-01-17 17:47:17 -08001517 def write(self, text):
1518 self.f.write(text)
1519
1520
Larry Hastings0759f842015-04-03 13:09:02 -07001521class BufferSeries:
1522 """
1523 Behaves like a "defaultlist".
1524 When you ask for an index that doesn't exist yet,
1525 the object grows the list until that item exists.
1526 So o[n] will always work.
1527
1528 Supports negative indices for actual items.
1529 e.g. o[-1] is an element immediately preceding o[0].
1530 """
1531
1532 def __init__(self):
1533 self._start = 0
1534 self._array = []
1535 self._constructor = _text_accumulator
1536
1537 def __getitem__(self, i):
1538 i -= self._start
1539 if i < 0:
1540 self._start += i
1541 prefix = [self._constructor() for x in range(-i)]
1542 self._array = prefix + self._array
1543 i = 0
1544 while i >= len(self._array):
1545 self._array.append(self._constructor())
1546 return self._array[i]
1547
1548 def clear(self):
1549 for ta in self._array:
1550 ta._text.clear()
1551
1552 def dump(self):
1553 texts = [ta.output() for ta in self._array]
1554 return "".join(texts)
1555
1556
Larry Hastingsbebf7352014-01-17 17:47:17 -08001557class Destination:
1558 def __init__(self, name, type, clinic, *args):
1559 self.name = name
1560 self.type = type
1561 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001562 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001563 if type not in valid_types:
1564 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1565 extra_arguments = 1 if type == "file" else 0
1566 if len(args) < extra_arguments:
1567 fail("Not enough arguments for destination " + name + " new " + type)
1568 if len(args) > extra_arguments:
1569 fail("Too many arguments for destination " + name + " new " + type)
1570 if type =='file':
1571 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001572 filename = clinic.filename
1573 d['path'] = filename
1574 dirname, basename = os.path.split(filename)
1575 if not dirname:
1576 dirname = '.'
1577 d['dirname'] = dirname
1578 d['basename'] = basename
1579 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001580 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001581
Larry Hastings0759f842015-04-03 13:09:02 -07001582 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001583
1584 def __repr__(self):
1585 if self.type == 'file':
1586 file_repr = " " + repr(self.filename)
1587 else:
1588 file_repr = ''
1589 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1590
1591 def clear(self):
1592 if self.type != 'buffer':
1593 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001594 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001595
1596 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001597 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001598
Larry Hastings31826802013-10-19 00:09:25 -07001599
1600# maps strings to Language objects.
1601# "languages" maps the name of the language ("C", "Python").
1602# "extensions" maps the file extension ("c", "py").
1603languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001604extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1605extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001606
1607
1608# maps strings to callables.
1609# these callables must be of the form:
1610# def foo(name, default, *, ...)
1611# The callable may have any number of keyword-only parameters.
1612# The callable must return a CConverter object.
1613# The callable should not call builtins.print.
1614converters = {}
1615
1616# maps strings to callables.
1617# these callables follow the same rules as those for "converters" above.
1618# note however that they will never be called with keyword-only parameters.
1619legacy_converters = {}
1620
1621
1622# maps strings to callables.
1623# these callables must be of the form:
1624# def foo(*, ...)
1625# The callable may have any number of keyword-only parameters.
1626# The callable must return a CConverter object.
1627# The callable should not call builtins.print.
1628return_converters = {}
1629
Larry Hastings7726ac92014-01-31 22:03:12 -08001630clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001631class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001632
1633 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001634preset block
1635everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001636methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001637docstring_prototype suppress
1638parser_prototype suppress
1639cpp_if suppress
1640cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001641
Larry Hastingsbebf7352014-01-17 17:47:17 -08001642preset original
1643everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001644methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001645docstring_prototype suppress
1646parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001647cpp_if suppress
1648cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001649
1650preset file
1651everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001652methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001653docstring_prototype suppress
1654parser_prototype suppress
1655impl_definition block
1656
1657preset buffer
1658everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001659methoddef_ifndef buffer 1
1660impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001661docstring_prototype suppress
1662impl_prototype suppress
1663parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001664
1665preset partial-buffer
1666everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001667methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001668docstring_prototype block
1669impl_prototype suppress
1670methoddef_define block
1671parser_prototype block
1672impl_definition block
1673
Larry Hastingsbebf7352014-01-17 17:47:17 -08001674"""
1675
Larry Hastings581ee362014-01-28 05:00:08 -08001676 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001677 # maps strings to Parser objects.
1678 # (instantiated from the "parsers" global.)
1679 self.parsers = {}
1680 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001681 if printer:
1682 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001683 self.printer = printer or BlockPrinter(language)
1684 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001685 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001686 self.filename = filename
1687 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001688 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001689 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001690
Larry Hastingsbebf7352014-01-17 17:47:17 -08001691 self.line_prefix = self.line_suffix = ''
1692
1693 self.destinations = {}
1694 self.add_destination("block", "buffer")
1695 self.add_destination("suppress", "suppress")
1696 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001697 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001698 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001699
Larry Hastings0759f842015-04-03 13:09:02 -07001700 d = self.get_destination_buffer
1701 self.destination_buffers = collections.OrderedDict((
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001702 ('cpp_if', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001703 ('docstring_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001704 ('docstring_definition', d('file')),
1705 ('methoddef_define', d('file')),
1706 ('impl_prototype', d('file')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001707 ('parser_prototype', d('suppress')),
Serhiy Storchaka1009bf12015-04-03 23:53:51 +03001708 ('parser_definition', d('file')),
1709 ('cpp_endif', d('file')),
1710 ('methoddef_ifndef', d('file', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001711 ('impl_definition', d('block')),
1712 ))
1713
Larry Hastings0759f842015-04-03 13:09:02 -07001714 self.destination_buffers_stack = []
1715 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001716
1717 self.presets = {}
1718 preset = None
1719 for line in self.presets_text.strip().split('\n'):
1720 line = line.strip()
1721 if not line:
1722 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001723 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001724 if name == 'preset':
1725 self.presets[value] = preset = collections.OrderedDict()
1726 continue
1727
Larry Hastings0759f842015-04-03 13:09:02 -07001728 if len(options):
1729 index = int(options[0])
1730 else:
1731 index = 0
1732 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001733
1734 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001735 for name in self.destination_buffers:
1736 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001737 continue
1738
Larry Hastings0759f842015-04-03 13:09:02 -07001739 assert name in self.destination_buffers
1740 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001741
Larry Hastings31826802013-10-19 00:09:25 -07001742 global clinic
1743 clinic = self
1744
Larry Hastingsbebf7352014-01-17 17:47:17 -08001745 def add_destination(self, name, type, *args):
1746 if name in self.destinations:
1747 fail("Destination already exists: " + repr(name))
1748 self.destinations[name] = Destination(name, type, self, *args)
1749
Larry Hastings0759f842015-04-03 13:09:02 -07001750 def get_destination(self, name):
1751 d = self.destinations.get(name)
1752 if not d:
1753 fail("Destination does not exist: " + repr(name))
1754 return d
1755
1756 def get_destination_buffer(self, name, item=0):
1757 d = self.get_destination(name)
1758 return d.buffers[item]
1759
Larry Hastings31826802013-10-19 00:09:25 -07001760 def parse(self, input):
1761 printer = self.printer
1762 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1763 for block in self.block_parser:
1764 dsl_name = block.dsl_name
1765 if dsl_name:
1766 if dsl_name not in self.parsers:
1767 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1768 self.parsers[dsl_name] = parsers[dsl_name](self)
1769 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001770 try:
1771 parser.parse(block)
1772 except Exception:
1773 fail('Exception raised during parsing:\n' +
1774 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001775 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001776
1777 second_pass_replacements = {}
1778
Larry Hastings0759f842015-04-03 13:09:02 -07001779 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001780 for name, destination in self.destinations.items():
1781 if destination.type == 'suppress':
1782 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001783 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001784
1785 if output:
1786
1787 block = Block("", dsl_name="clinic", output=output)
1788
1789 if destination.type == 'buffer':
1790 block.input = "dump " + name + "\n"
1791 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1792 printer.write("\n")
1793 printer.print_block(block)
1794 continue
1795
1796 if destination.type == 'file':
1797 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001798 dirname = os.path.dirname(destination.filename)
1799 try:
1800 os.makedirs(dirname)
1801 except FileExistsError:
1802 if not os.path.isdir(dirname):
1803 fail("Can't write to destination {}, "
1804 "can't make directory {}!".format(
1805 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001806 if self.verify:
1807 with open(destination.filename, "rt") as f:
1808 parser_2 = BlockParser(f.read(), language=self.language)
1809 blocks = list(parser_2)
1810 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1811 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001812 except FileNotFoundError:
1813 pass
1814
1815 block.input = 'preserve\n'
1816 printer_2 = BlockPrinter(self.language)
1817 printer_2.print_block(block)
1818 with open(destination.filename, "wt") as f:
1819 f.write(printer_2.f.getvalue())
1820 continue
1821 text = printer.f.getvalue()
1822
1823 if second_pass_replacements:
1824 printer_2 = BlockPrinter(self.language)
1825 parser_2 = BlockParser(text, self.language)
1826 changed = False
1827 for block in parser_2:
1828 if block.dsl_name:
1829 for id, replacement in second_pass_replacements.items():
1830 if id in block.output:
1831 changed = True
1832 block.output = block.output.replace(id, replacement)
1833 printer_2.print_block(block)
1834 if changed:
1835 text = printer_2.f.getvalue()
1836
1837 return text
1838
Larry Hastings31826802013-10-19 00:09:25 -07001839
1840 def _module_and_class(self, fields):
1841 """
1842 fields should be an iterable of field names.
1843 returns a tuple of (module, class).
1844 the module object could actually be self (a clinic object).
1845 this function is only ever used to find the parent of where
1846 a new class/module should go.
1847 """
1848 in_classes = False
1849 parent = module = self
1850 cls = None
1851 so_far = []
1852
1853 for field in fields:
1854 so_far.append(field)
1855 if not in_classes:
1856 child = parent.modules.get(field)
1857 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001858 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001859 continue
1860 in_classes = True
1861 if not hasattr(parent, 'classes'):
1862 return module, cls
1863 child = parent.classes.get(field)
1864 if not child:
1865 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1866 cls = parent = child
1867
1868 return module, cls
1869
1870
Larry Hastings581ee362014-01-28 05:00:08 -08001871def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001872 extension = os.path.splitext(filename)[1][1:]
1873 if not extension:
1874 fail("Can't extract file type for file " + repr(filename))
1875
1876 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001877 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001878 except KeyError:
1879 fail("Can't identify file type for file " + repr(filename))
1880
Larry Hastings31826802013-10-19 00:09:25 -07001881 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001882 raw = f.read()
1883
Larry Hastings2623c8c2014-02-08 22:15:29 -08001884 # exit quickly if there are no clinic markers in the file
1885 find_start_re = BlockParser("", language).find_start_re
1886 if not find_start_re.search(raw):
1887 return
1888
1889 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001890 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001891 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001892 return
Larry Hastings31826802013-10-19 00:09:25 -07001893
1894 directory = os.path.dirname(filename) or '.'
1895
1896 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001897 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001898 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1899 with open(tmpfilename, "wb") as f:
1900 f.write(bytes)
1901 os.replace(tmpfilename, output or filename)
1902
1903
Larry Hastings581ee362014-01-28 05:00:08 -08001904def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001905 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001906 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1907 if length:
1908 s = s[:length]
1909 return s
Larry Hastings31826802013-10-19 00:09:25 -07001910
1911
1912
1913
1914class PythonParser:
1915 def __init__(self, clinic):
1916 pass
1917
1918 def parse(self, block):
1919 s = io.StringIO()
1920 with OverrideStdioWith(s):
1921 exec(block.input)
1922 block.output = s.getvalue()
1923
1924
1925class Module:
1926 def __init__(self, name, module=None):
1927 self.name = name
1928 self.module = self.parent = module
1929
1930 self.modules = collections.OrderedDict()
1931 self.classes = collections.OrderedDict()
1932 self.functions = []
1933
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001934 def __repr__(self):
1935 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1936
Larry Hastings31826802013-10-19 00:09:25 -07001937class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001938 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001939 self.name = name
1940 self.module = module
1941 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001942 self.typedef = typedef
1943 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001944 self.parent = cls or module
1945
1946 self.classes = collections.OrderedDict()
1947 self.functions = []
1948
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001949 def __repr__(self):
1950 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1951
Larry Hastings8666e652014-01-12 14:12:59 -08001952unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001953
Larry Hastings8666e652014-01-12 14:12:59 -08001954__abs__
1955__add__
1956__and__
1957__bytes__
1958__call__
1959__complex__
1960__delitem__
1961__divmod__
1962__eq__
1963__float__
1964__floordiv__
1965__ge__
1966__getattr__
1967__getattribute__
1968__getitem__
1969__gt__
1970__hash__
1971__iadd__
1972__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08001973__ifloordiv__
1974__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02001975__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08001976__imod__
1977__imul__
1978__index__
1979__int__
1980__invert__
1981__ior__
1982__ipow__
1983__irshift__
1984__isub__
1985__iter__
1986__itruediv__
1987__ixor__
1988__le__
1989__len__
1990__lshift__
1991__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02001992__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08001993__mod__
1994__mul__
1995__neg__
1996__new__
1997__next__
1998__or__
1999__pos__
2000__pow__
2001__radd__
2002__rand__
2003__rdivmod__
2004__repr__
2005__rfloordiv__
2006__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02002007__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08002008__rmod__
2009__rmul__
2010__ror__
2011__round__
2012__rpow__
2013__rrshift__
2014__rshift__
2015__rsub__
2016__rtruediv__
2017__rxor__
2018__setattr__
2019__setitem__
2020__str__
2021__sub__
2022__truediv__
2023__xor__
2024
2025""".strip().split())
2026
2027
Larry Hastings5c661892014-01-24 06:17:25 -08002028INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
2029INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
2030""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07002031
2032class Function:
2033 """
2034 Mutable duck type for inspect.Function.
2035
2036 docstring - a str containing
2037 * embedded line breaks
2038 * text outdented to the left margin
2039 * no trailing whitespace.
2040 It will always be true that
2041 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
2042 """
2043
2044 def __init__(self, parameters=None, *, name,
2045 module, cls=None, c_basename=None,
2046 full_name=None,
2047 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08002048 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002049 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07002050 self.parameters = parameters or collections.OrderedDict()
2051 self.return_annotation = return_annotation
2052 self.name = name
2053 self.full_name = full_name
2054 self.module = module
2055 self.cls = cls
2056 self.parent = cls or module
2057 self.c_basename = c_basename
2058 self.return_converter = return_converter
2059 self.docstring = docstring or ''
2060 self.kind = kind
2061 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08002062 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08002063 # docstring_only means "don't generate a machine-readable
2064 # signature, just a normal docstring". it's True for
2065 # functions with optional groups because we can't represent
2066 # those accurately with inspect.Signature in 3.4.
2067 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08002068
Larry Hastings7726ac92014-01-31 22:03:12 -08002069 self.rendered_parameters = None
2070
2071 __render_parameters__ = None
2072 @property
2073 def render_parameters(self):
2074 if not self.__render_parameters__:
2075 self.__render_parameters__ = l = []
2076 for p in self.parameters.values():
2077 p = p.copy()
2078 p.converter.pre_render()
2079 l.append(p)
2080 return self.__render_parameters__
2081
Larry Hastingsebdcb502013-11-23 14:54:00 -08002082 @property
2083 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08002084 if self.kind in (METHOD_INIT, METHOD_NEW):
2085 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002086 flags = []
2087 if self.kind == CLASS_METHOD:
2088 flags.append('METH_CLASS')
2089 elif self.kind == STATIC_METHOD:
2090 flags.append('METH_STATIC')
2091 else:
2092 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
2093 if self.coexist:
2094 flags.append('METH_COEXIST')
2095 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07002096
2097 def __repr__(self):
2098 return '<clinic.Function ' + self.name + '>'
2099
Larry Hastings7726ac92014-01-31 22:03:12 -08002100 def copy(self, **overrides):
2101 kwargs = {
2102 'name': self.name, 'module': self.module, 'parameters': self.parameters,
2103 'cls': self.cls, 'c_basename': self.c_basename,
2104 'full_name': self.full_name,
2105 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
2106 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08002107 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08002108 }
2109 kwargs.update(overrides)
2110 f = Function(**kwargs)
2111
2112 parameters = collections.OrderedDict()
2113 for name, value in f.parameters.items():
2114 value = value.copy(function=f)
2115 parameters[name] = value
2116 f.parameters = parameters
2117 return f
2118
Larry Hastings31826802013-10-19 00:09:25 -07002119
2120class Parameter:
2121 """
2122 Mutable duck type of inspect.Parameter.
2123 """
2124
2125 def __init__(self, name, kind, *, default=_empty,
2126 function, converter, annotation=_empty,
2127 docstring=None, group=0):
2128 self.name = name
2129 self.kind = kind
2130 self.default = default
2131 self.function = function
2132 self.converter = converter
2133 self.annotation = annotation
2134 self.docstring = docstring or ''
2135 self.group = group
2136
2137 def __repr__(self):
2138 return '<clinic.Parameter ' + self.name + '>'
2139
2140 def is_keyword_only(self):
2141 return self.kind == inspect.Parameter.KEYWORD_ONLY
2142
Larry Hastings2623c8c2014-02-08 22:15:29 -08002143 def is_positional_only(self):
2144 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2145
Larry Hastings7726ac92014-01-31 22:03:12 -08002146 def copy(self, **overrides):
2147 kwargs = {
2148 'name': self.name, 'kind': self.kind, 'default':self.default,
2149 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2150 'docstring': self.docstring, 'group': self.group,
2151 }
2152 kwargs.update(overrides)
2153 if 'converter' not in overrides:
2154 converter = copy.copy(self.converter)
2155 converter.function = kwargs['function']
2156 kwargs['converter'] = converter
2157 return Parameter(**kwargs)
2158
2159
2160
2161class LandMine:
2162 # try to access any
2163 def __init__(self, message):
2164 self.__message__ = message
2165
2166 def __repr__(self):
2167 return '<LandMine ' + repr(self.__message__) + ">"
2168
2169 def __getattribute__(self, name):
2170 if name in ('__repr__', '__message__'):
2171 return super().__getattribute__(name)
2172 # raise RuntimeError(repr(name))
2173 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002174
Larry Hastings31826802013-10-19 00:09:25 -07002175
2176def add_c_converter(f, name=None):
2177 if not name:
2178 name = f.__name__
2179 if not name.endswith('_converter'):
2180 return f
2181 name = name[:-len('_converter')]
2182 converters[name] = f
2183 return f
2184
2185def add_default_legacy_c_converter(cls):
2186 # automatically add converter for default format unit
2187 # (but without stomping on the existing one if it's already
2188 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002189 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002190 (cls.format_unit not in legacy_converters)):
2191 legacy_converters[cls.format_unit] = cls
2192 return cls
2193
2194def add_legacy_c_converter(format_unit, **kwargs):
2195 """
2196 Adds a legacy converter.
2197 """
2198 def closure(f):
2199 if not kwargs:
2200 added_f = f
2201 else:
2202 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002203 if format_unit:
2204 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002205 return f
2206 return closure
2207
2208class CConverterAutoRegister(type):
2209 def __init__(cls, name, bases, classdict):
2210 add_c_converter(cls)
2211 add_default_legacy_c_converter(cls)
2212
2213class CConverter(metaclass=CConverterAutoRegister):
2214 """
2215 For the init function, self, name, function, and default
2216 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002217 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002218 """
2219
Larry Hastings7726ac92014-01-31 22:03:12 -08002220 # The C name to use for this variable.
2221 name = None
2222
2223 # The Python name to use for this variable.
2224 py_name = None
2225
Larry Hastings78cf85c2014-01-04 12:44:57 -08002226 # The C type to use for this variable.
2227 # 'type' should be a Python string specifying the type, e.g. "int".
2228 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002229 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002230
2231 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002232 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002233 # Or the magic value "unknown" if this value is a cannot be evaluated
2234 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2235 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002236 default = unspecified
2237
Larry Hastings4a55fc52014-01-12 11:09:57 -08002238 # If not None, default must be isinstance() of this type.
2239 # (You can also specify a tuple of types.)
2240 default_type = None
2241
Larry Hastings31826802013-10-19 00:09:25 -07002242 # "default" converted into a C value, as a string.
2243 # Or None if there is no default.
2244 c_default = None
2245
Larry Hastings2a727912014-01-16 11:32:01 -08002246 # "default" converted into a Python value, as a string.
2247 # Or None if there is no default.
2248 py_default = None
2249
Larry Hastingsabc716b2013-11-20 09:13:52 -08002250 # The default value used to initialize the C variable when
2251 # there is no default, but not specifying a default may
2252 # result in an "uninitialized variable" warning. This can
2253 # easily happen when using option groups--although
2254 # properly-written code won't actually use the variable,
2255 # the variable does get passed in to the _impl. (Ah, if
2256 # only dataflow analysis could inline the static function!)
2257 #
2258 # This value is specified as a string.
2259 # Every non-abstract subclass should supply a valid value.
2260 c_ignored_default = 'NULL'
2261
Larry Hastings31826802013-10-19 00:09:25 -07002262 # The C converter *function* to be used, if any.
2263 # (If this is not None, format_unit must be 'O&'.)
2264 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002265
Larry Hastings78cf85c2014-01-04 12:44:57 -08002266 # Should Argument Clinic add a '&' before the name of
2267 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002268 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002269
2270 # Should Argument Clinic add a '&' before the name of
2271 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002272 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002273
2274 #############################################################
2275 #############################################################
2276 ## You shouldn't need to read anything below this point to ##
2277 ## write your own converter functions. ##
2278 #############################################################
2279 #############################################################
2280
2281 # The "format unit" to specify for this variable when
2282 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2283 # Custom converters should always use the default value of 'O&'.
2284 format_unit = 'O&'
2285
2286 # What encoding do we want for this variable? Only used
2287 # by format units starting with 'e'.
2288 encoding = None
2289
Larry Hastings77561cc2014-01-07 12:13:13 -08002290 # Should this object be required to be a subclass of a specific type?
2291 # If not None, should be a string representing a pointer to a
2292 # PyTypeObject (e.g. "&PyUnicode_Type").
2293 # Only used by the 'O!' format unit (and the "object" converter).
2294 subclass_of = None
2295
Larry Hastings78cf85c2014-01-04 12:44:57 -08002296 # Do we want an adjacent '_length' variable for this variable?
2297 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002298 length = False
2299
Larry Hastings5c661892014-01-24 06:17:25 -08002300 # Should we show this parameter in the generated
2301 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002302 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002303 show_in_signature = True
2304
2305 # Overrides the name used in a text signature.
2306 # The name used for a "self" parameter must be one of
2307 # self, type, or module; however users can set their own.
2308 # This lets the self_converter overrule the user-settable
2309 # name, *just* for the text signature.
2310 # Only set by self_converter.
2311 signature_name = None
2312
2313 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002314 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 -07002315 self.name = name
Larry Hastings7726ac92014-01-31 22:03:12 -08002316 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002317
2318 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002319 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002320 if isinstance(self.default_type, type):
2321 types_str = self.default_type.__name__
2322 else:
2323 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2324 fail("{}: default value {!r} for field {} is not of type {}".format(
2325 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002326 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002327
Larry Hastingsb4705752014-01-18 21:54:15 -08002328 if c_default:
2329 self.c_default = c_default
2330 if py_default:
2331 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002332
Larry Hastings31826802013-10-19 00:09:25 -07002333 if annotation != unspecified:
2334 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002335
2336 # this is deliberate, to prevent you from caching information
2337 # about the function in the init.
2338 # (that breaks if we get cloned.)
2339 # so after this change we will noisily fail.
2340 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002341 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002342 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002343
2344 def converter_init(self):
2345 pass
2346
2347 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002348 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002349
Larry Hastings5c661892014-01-24 06:17:25 -08002350 def _render_self(self, parameter, data):
2351 self.parameter = parameter
2352 original_name = self.name
2353 name = ensure_legal_c_identifier(original_name)
2354
2355 # impl_arguments
2356 s = ("&" if self.impl_by_reference else "") + name
2357 data.impl_arguments.append(s)
2358 if self.length:
2359 data.impl_arguments.append(self.length_name())
2360
2361 # impl_parameters
2362 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2363 if self.length:
2364 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2365
2366 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002367 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002368 original_name = self.name
2369 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002370
2371 # declarations
2372 d = self.declaration()
2373 data.declarations.append(d)
2374
2375 # initializers
2376 initializers = self.initialize()
2377 if initializers:
2378 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2379
Larry Hastingsc2047262014-01-25 20:43:29 -08002380 # modifications
2381 modifications = self.modify()
2382 if modifications:
2383 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2384
Larry Hastings31826802013-10-19 00:09:25 -07002385 # keywords
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03002386 if parameter.is_positional_only():
2387 data.keywords.append('')
2388 else:
2389 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002390
2391 # format_units
2392 if self.is_optional() and '|' not in data.format_units:
2393 data.format_units.append('|')
2394 if parameter.is_keyword_only() and '$' not in data.format_units:
2395 data.format_units.append('$')
2396 data.format_units.append(self.format_unit)
2397
2398 # parse_arguments
2399 self.parse_argument(data.parse_arguments)
2400
Larry Hastings31826802013-10-19 00:09:25 -07002401 # cleanup
2402 cleanup = self.cleanup()
2403 if cleanup:
2404 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2405
Larry Hastings5c661892014-01-24 06:17:25 -08002406 def render(self, parameter, data):
2407 """
2408 parameter is a clinic.Parameter instance.
2409 data is a CRenderData instance.
2410 """
2411 self._render_self(parameter, data)
2412 self._render_non_self(parameter, data)
2413
Larry Hastingsebdcb502013-11-23 14:54:00 -08002414 def length_name(self):
2415 """Computes the name of the associated "length" variable."""
2416 if not self.length:
2417 return None
2418 return ensure_legal_c_identifier(self.name) + "_length"
2419
Larry Hastings31826802013-10-19 00:09:25 -07002420 # Why is this one broken out separately?
2421 # For "positional-only" function parsing,
2422 # which generates a bunch of PyArg_ParseTuple calls.
2423 def parse_argument(self, list):
2424 assert not (self.converter and self.encoding)
2425 if self.format_unit == 'O&':
2426 assert self.converter
2427 list.append(self.converter)
2428
2429 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002430 list.append(c_repr(self.encoding))
2431 elif self.subclass_of:
2432 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002433
Larry Hastingsebdcb502013-11-23 14:54:00 -08002434 legal_name = ensure_legal_c_identifier(self.name)
2435 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002436 list.append(s)
2437
Larry Hastingsebdcb502013-11-23 14:54:00 -08002438 if self.length:
2439 list.append("&" + self.length_name())
2440
Larry Hastings31826802013-10-19 00:09:25 -07002441 #
2442 # All the functions after here are intended as extension points.
2443 #
2444
2445 def simple_declaration(self, by_reference=False):
2446 """
2447 Computes the basic declaration of the variable.
2448 Used in computing the prototype declaration and the
2449 variable declaration.
2450 """
2451 prototype = [self.type]
2452 if by_reference or not self.type.endswith('*'):
2453 prototype.append(" ")
2454 if by_reference:
2455 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002456 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002457 return "".join(prototype)
2458
2459 def declaration(self):
2460 """
2461 The C statement to declare this variable.
2462 """
2463 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002464 default = self.c_default
2465 if not default and self.parameter.group:
2466 default = self.c_ignored_default
2467 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002468 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002469 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002470 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002471 if self.length:
2472 declaration.append('\nPy_ssize_clean_t ')
2473 declaration.append(self.length_name())
2474 declaration.append(';')
Serhiy Storchakaebe95fd2016-06-09 16:02:15 +03002475 return "".join(declaration)
Larry Hastings31826802013-10-19 00:09:25 -07002476
2477 def initialize(self):
2478 """
2479 The C statements required to set up this variable before parsing.
2480 Returns a string containing this code indented at column 0.
2481 If no initialization is necessary, returns an empty string.
2482 """
2483 return ""
2484
Larry Hastingsc2047262014-01-25 20:43:29 -08002485 def modify(self):
2486 """
2487 The C statements required to modify this variable after parsing.
2488 Returns a string containing this code indented at column 0.
2489 If no initialization is necessary, returns an empty string.
2490 """
2491 return ""
2492
Larry Hastings31826802013-10-19 00:09:25 -07002493 def cleanup(self):
2494 """
2495 The C statements required to clean up after this variable.
2496 Returns a string containing this code indented at column 0.
2497 If no cleanup is necessary, returns an empty string.
2498 """
2499 return ""
2500
Larry Hastings7726ac92014-01-31 22:03:12 -08002501 def pre_render(self):
2502 """
2503 A second initialization function, like converter_init,
2504 called just before rendering.
2505 You are permitted to examine self.function here.
2506 """
2507 pass
2508
Larry Hastings31826802013-10-19 00:09:25 -07002509
2510class bool_converter(CConverter):
2511 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002512 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002513 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002514 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002515
2516 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002517 if self.default is not unspecified:
2518 self.default = bool(self.default)
2519 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002520
2521class char_converter(CConverter):
2522 type = 'char'
Larry Hastings7f90cba2015-04-15 23:02:12 -04002523 default_type = (bytes, bytearray)
Larry Hastings31826802013-10-19 00:09:25 -07002524 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002525 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002526
Larry Hastings4a55fc52014-01-12 11:09:57 -08002527 def converter_init(self):
Larry Hastings7f90cba2015-04-15 23:02:12 -04002528 if isinstance(self.default, self.default_type) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002529 fail("char_converter: illegal default value " + repr(self.default))
2530
2531
Larry Hastings31826802013-10-19 00:09:25 -07002532@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002533class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002534 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002535 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002536 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002537 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002538
2539 def converter_init(self, *, bitwise=False):
2540 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002541 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002542
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002543class byte_converter(unsigned_char_converter): pass
2544
Larry Hastings31826802013-10-19 00:09:25 -07002545class short_converter(CConverter):
2546 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002547 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002548 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002549 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002550
2551class unsigned_short_converter(CConverter):
2552 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002553 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002554 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002555 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002556
2557 def converter_init(self, *, bitwise=False):
2558 if not bitwise:
2559 fail("Unsigned shorts must be bitwise (for now).")
2560
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002561@add_legacy_c_converter('C', accept={str})
Larry Hastings31826802013-10-19 00:09:25 -07002562class int_converter(CConverter):
2563 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002564 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002565 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002566 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002567
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002568 def converter_init(self, *, accept={int}, type=None):
2569 if accept == {str}:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002570 self.format_unit = 'C'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002571 elif accept != {int}:
2572 fail("int_converter: illegal 'accept' argument " + repr(accept))
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002573 if type != None:
2574 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002575
2576class unsigned_int_converter(CConverter):
2577 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002578 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002579 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002580 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002581
2582 def converter_init(self, *, bitwise=False):
2583 if not bitwise:
2584 fail("Unsigned ints must be bitwise (for now).")
2585
2586class long_converter(CConverter):
2587 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002588 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002589 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002590 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002591
2592class unsigned_long_converter(CConverter):
2593 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002594 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002595 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002596 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002597
2598 def converter_init(self, *, bitwise=False):
2599 if not bitwise:
2600 fail("Unsigned longs must be bitwise (for now).")
2601
Benjamin Petersoncc854492016-09-08 09:29:11 -07002602class long_long_converter(CConverter):
2603 type = 'long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002604 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002605 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002606 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002607
Benjamin Petersoncc854492016-09-08 09:29:11 -07002608class unsigned_long_long_converter(CConverter):
2609 type = 'unsigned long long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002610 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002611 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002612 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002613
2614 def converter_init(self, *, bitwise=False):
2615 if not bitwise:
Benjamin Petersoncc854492016-09-08 09:29:11 -07002616 fail("Unsigned long long must be bitwise (for now).")
Larry Hastings31826802013-10-19 00:09:25 -07002617
2618class Py_ssize_t_converter(CConverter):
2619 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002620 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002621 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002622 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002623
2624
2625class float_converter(CConverter):
2626 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002627 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002628 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002629 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002630
2631class double_converter(CConverter):
2632 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002633 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002634 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002635 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002636
2637
2638class Py_complex_converter(CConverter):
2639 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002640 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002641 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002642 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002643
2644
2645class object_converter(CConverter):
2646 type = 'PyObject *'
2647 format_unit = 'O'
2648
Larry Hastings4a55fc52014-01-12 11:09:57 -08002649 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2650 if converter:
2651 if subclass_of:
2652 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2653 self.format_unit = 'O&'
2654 self.converter = converter
2655 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002656 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002657 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002658
Larry Hastings77561cc2014-01-07 12:13:13 -08002659 if type is not None:
2660 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002661
2662
Larry Hastings7f90cba2015-04-15 23:02:12 -04002663#
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002664# We define three conventions for buffer types in the 'accept' argument:
2665#
2666# buffer : any object supporting the buffer interface
2667# rwbuffer: any object supporting the buffer interface, but must be writeable
2668# robuffer: any object supporting the buffer interface, but must not be writeable
Larry Hastings7f90cba2015-04-15 23:02:12 -04002669#
2670
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002671class buffer: pass
2672class rwbuffer: pass
2673class robuffer: pass
2674
Larry Hastings38337d12015-05-07 23:30:09 -07002675def str_converter_key(types, encoding, zeroes):
2676 return (frozenset(types), bool(encoding), bool(zeroes))
2677
2678str_converter_argument_map = {}
2679
Larry Hastings31826802013-10-19 00:09:25 -07002680class str_converter(CConverter):
2681 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002682 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002683 format_unit = 's'
2684
Larry Hastings38337d12015-05-07 23:30:09 -07002685 def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002686
Larry Hastings38337d12015-05-07 23:30:09 -07002687 key = str_converter_key(accept, encoding, zeroes)
2688 format_unit = str_converter_argument_map.get(key)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002689 if not format_unit:
Larry Hastings38337d12015-05-07 23:30:09 -07002690 fail("str_converter: illegal combination of arguments", key)
2691
Larry Hastingsebdcb502013-11-23 14:54:00 -08002692 self.format_unit = format_unit
Larry Hastings38337d12015-05-07 23:30:09 -07002693 self.length = bool(zeroes)
2694 if encoding:
2695 if self.default not in (Null, None, unspecified):
2696 fail("str_converter: Argument Clinic doesn't support default values for encoded strings")
2697 self.encoding = encoding
2698 self.type = 'char *'
2699 # sorry, clinic can't support preallocated buffers
2700 # for es# and et#
2701 self.c_default = "NULL"
2702
2703 def cleanup(self):
2704 if self.encoding:
2705 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002706 return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
Larry Hastings38337d12015-05-07 23:30:09 -07002707
2708#
2709# This is the fourth or fifth rewrite of registering all the
2710# crazy string converter format units. Previous approaches hid
2711# bugs--generally mismatches between the semantics of the format
2712# unit and the arguments necessary to represent those semantics
2713# properly. Hopefully with this approach we'll get it 100% right.
2714#
2715# The r() function (short for "register") both registers the
2716# mapping from arguments to format unit *and* registers the
2717# legacy C converter for that format unit.
2718#
2719def r(format_unit, *, accept, encoding=False, zeroes=False):
2720 if not encoding and format_unit != 's':
2721 # add the legacy c converters here too.
2722 #
2723 # note: add_legacy_c_converter can't work for
2724 # es, es#, et, or et#
2725 # because of their extra encoding argument
2726 #
2727 # also don't add the converter for 's' because
2728 # the metaclass for CConverter adds it for us.
2729 kwargs = {}
2730 if accept != {str}:
2731 kwargs['accept'] = accept
2732 if zeroes:
2733 kwargs['zeroes'] = True
2734 added_f = functools.partial(str_converter, **kwargs)
2735 legacy_converters[format_unit] = added_f
2736
2737 d = str_converter_argument_map
2738 key = str_converter_key(accept, encoding, zeroes)
2739 if key in d:
2740 sys.exit("Duplicate keys specified for str_converter_argument_map!")
2741 d[key] = format_unit
2742
2743r('es', encoding=True, accept={str})
2744r('es#', encoding=True, zeroes=True, accept={str})
2745r('et', encoding=True, accept={bytes, bytearray, str})
2746r('et#', encoding=True, zeroes=True, accept={bytes, bytearray, str})
2747r('s', accept={str})
2748r('s#', zeroes=True, accept={robuffer, str})
2749r('y', accept={robuffer})
2750r('y#', zeroes=True, accept={robuffer})
2751r('z', accept={str, NoneType})
2752r('z#', zeroes=True, accept={robuffer, str, NoneType})
2753del r
Larry Hastings31826802013-10-19 00:09:25 -07002754
2755
2756class PyBytesObject_converter(CConverter):
2757 type = 'PyBytesObject *'
2758 format_unit = 'S'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002759 # accept = {bytes}
Larry Hastings31826802013-10-19 00:09:25 -07002760
2761class PyByteArrayObject_converter(CConverter):
2762 type = 'PyByteArrayObject *'
2763 format_unit = 'Y'
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002764 # accept = {bytearray}
Larry Hastings31826802013-10-19 00:09:25 -07002765
2766class unicode_converter(CConverter):
2767 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002768 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002769 format_unit = 'U'
2770
Larry Hastings38337d12015-05-07 23:30:09 -07002771@add_legacy_c_converter('u#', zeroes=True)
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002772@add_legacy_c_converter('Z', accept={str, NoneType})
Larry Hastings38337d12015-05-07 23:30:09 -07002773@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
Larry Hastings31826802013-10-19 00:09:25 -07002774class Py_UNICODE_converter(CConverter):
2775 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002776 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002777 format_unit = 'u'
2778
Larry Hastings38337d12015-05-07 23:30:09 -07002779 def converter_init(self, *, accept={str}, zeroes=False):
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002780 format_unit = 'Z' if accept=={str, NoneType} else 'u'
Larry Hastings38337d12015-05-07 23:30:09 -07002781 if zeroes:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002782 format_unit += '#'
2783 self.length = True
2784 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002785
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002786@add_legacy_c_converter('s*', accept={str, buffer})
2787@add_legacy_c_converter('z*', accept={str, buffer, NoneType})
2788@add_legacy_c_converter('w*', accept={rwbuffer})
Larry Hastings31826802013-10-19 00:09:25 -07002789class Py_buffer_converter(CConverter):
2790 type = 'Py_buffer'
2791 format_unit = 'y*'
2792 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002793 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002794
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002795 def converter_init(self, *, accept={buffer}):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002796 if self.default not in (unspecified, None):
2797 fail("The only legal default value for Py_buffer is None.")
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002798
Larry Hastings3f144c22014-01-06 10:34:00 -08002799 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002800
Larry Hastingsdbfdc382015-05-04 06:59:46 -07002801 if accept == {str, buffer, NoneType}:
2802 format_unit = 'z*'
2803 elif accept == {str, buffer}:
2804 format_unit = 's*'
2805 elif accept == {buffer}:
2806 format_unit = 'y*'
2807 elif accept == {rwbuffer}:
2808 format_unit = 'w*'
Larry Hastings31826802013-10-19 00:09:25 -07002809 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002810 fail("Py_buffer_converter: illegal combination of arguments")
2811
2812 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002813
2814 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002815 name = ensure_legal_c_identifier(self.name)
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002816 return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002817
2818
Larry Hastings5c661892014-01-24 06:17:25 -08002819def correct_name_for_self(f):
2820 if f.kind in (CALLABLE, METHOD_INIT):
2821 if f.cls:
2822 return "PyObject *", "self"
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +03002823 return "PyObject *", "module"
Larry Hastings5c661892014-01-24 06:17:25 -08002824 if f.kind == STATIC_METHOD:
2825 return "void *", "null"
2826 if f.kind in (CLASS_METHOD, METHOD_NEW):
2827 return "PyTypeObject *", "type"
2828 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2829
Larry Hastingsc2047262014-01-25 20:43:29 -08002830def required_type_for_self_for_parser(f):
2831 type, _ = correct_name_for_self(f)
2832 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2833 return type
2834 return None
2835
Larry Hastings5c661892014-01-24 06:17:25 -08002836
Larry Hastingsebdcb502013-11-23 14:54:00 -08002837class self_converter(CConverter):
2838 """
2839 A special-case converter:
2840 this is the default converter used for "self".
2841 """
Larry Hastings5c661892014-01-24 06:17:25 -08002842 type = None
2843 format_unit = ''
2844
Larry Hastings78cf85c2014-01-04 12:44:57 -08002845 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08002846 self.specified_type = type
2847
2848 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002849 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002850 default_type, default_name = correct_name_for_self(f)
2851 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08002852 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002853
Larry Hastings5c661892014-01-24 06:17:25 -08002854 kind = self.function.kind
2855 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2856
2857 if (kind == STATIC_METHOD) or new_or_init:
2858 self.show_in_signature = False
2859
2860 # tp_new (METHOD_NEW) functions are of type newfunc:
2861 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2862 # PyTypeObject is a typedef for struct _typeobject.
2863 #
2864 # tp_init (METHOD_INIT) functions are of type initproc:
2865 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2866 #
2867 # All other functions generated by Argument Clinic are stored in
2868 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2869 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2870 # However! We habitually cast these functions to PyCFunction,
2871 # since functions that accept keyword arguments don't fit this signature
2872 # but are stored there anyway. So strict type equality isn't important
2873 # for these functions.
2874 #
2875 # So:
2876 #
2877 # * The name of the first parameter to the impl and the parsing function will always
2878 # be self.name.
2879 #
2880 # * The type of the first parameter to the impl will always be of self.type.
2881 #
2882 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2883 # * The type of the first parameter to the parsing function is also self.type.
2884 # This means that if you step into the parsing function, your "self" parameter
2885 # is of the correct type, which may make debugging more pleasant.
2886 #
2887 # * Else if the function is tp_new (METHOD_NEW):
2888 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2889 # so the type signature of the function call is an exact match.
2890 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2891 # in the impl call.
2892 #
2893 # * Else if the function is tp_init (METHOD_INIT):
2894 # * The type of the first parameter to the parsing function is "PyObject *",
2895 # so the type signature of the function call is an exact match.
2896 # * If self.type != "PyObject *", we cast the first parameter to self.type
2897 # in the impl call.
2898
2899 @property
2900 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002901 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002902
Larry Hastingsebdcb502013-11-23 14:54:00 -08002903 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002904 """
2905 parameter is a clinic.Parameter instance.
2906 data is a CRenderData instance.
2907 """
2908 if self.function.kind == STATIC_METHOD:
2909 return
2910
2911 self._render_self(parameter, data)
2912
2913 if self.type != self.parser_type:
2914 # insert cast to impl_argument[0], aka self.
2915 # we know we're in the first slot in all the CRenderData lists,
2916 # because we render parameters in order, and self is always first.
2917 assert len(data.impl_arguments) == 1
2918 assert data.impl_arguments[0] == self.name
2919 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
2920
2921 def set_template_dict(self, template_dict):
2922 template_dict['self_name'] = self.name
2923 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08002924 kind = self.function.kind
2925 cls = self.function.cls
2926
2927 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
2928 if kind == METHOD_NEW:
2929 passed_in_type = self.name
2930 else:
2931 passed_in_type = 'Py_TYPE({})'.format(self.name)
2932
2933 line = '({passed_in_type} == {type_object}) &&\n '
2934 d = {
2935 'type_object': self.function.cls.type_object,
2936 'passed_in_type': passed_in_type
2937 }
2938 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002939
Larry Hastings31826802013-10-19 00:09:25 -07002940
2941
2942def add_c_return_converter(f, name=None):
2943 if not name:
2944 name = f.__name__
2945 if not name.endswith('_return_converter'):
2946 return f
2947 name = name[:-len('_return_converter')]
2948 return_converters[name] = f
2949 return f
2950
2951
2952class CReturnConverterAutoRegister(type):
2953 def __init__(cls, name, bases, classdict):
2954 add_c_return_converter(cls)
2955
2956class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2957
Larry Hastings78cf85c2014-01-04 12:44:57 -08002958 # The C type to use for this variable.
2959 # 'type' should be a Python string specifying the type, e.g. "int".
2960 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002961 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002962
2963 # The Python default value for this parameter, as a Python value.
2964 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002965 default = None
2966
Larry Hastings2a727912014-01-16 11:32:01 -08002967 def __init__(self, *, py_default=None, **kwargs):
2968 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002969 try:
2970 self.return_converter_init(**kwargs)
2971 except TypeError as e:
2972 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2973 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2974
2975 def return_converter_init(self):
2976 pass
2977
2978 def declare(self, data, name="_return_value"):
2979 line = []
2980 add = line.append
2981 add(self.type)
2982 if not self.type.endswith('*'):
2983 add(' ')
2984 add(name + ';')
2985 data.declarations.append(''.join(line))
2986 data.return_value = name
2987
2988 def err_occurred_if(self, expr, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002989 data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
Larry Hastings31826802013-10-19 00:09:25 -07002990
2991 def err_occurred_if_null_pointer(self, variable, data):
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03002992 data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
Larry Hastings31826802013-10-19 00:09:25 -07002993
2994 def render(self, function, data):
2995 """
2996 function is a clinic.Function instance.
2997 data is a CRenderData instance.
2998 """
2999 pass
3000
3001add_c_return_converter(CReturnConverter, 'object')
3002
Larry Hastings78cf85c2014-01-04 12:44:57 -08003003class NoneType_return_converter(CReturnConverter):
3004 def render(self, function, data):
3005 self.declare(data)
3006 data.return_conversion.append('''
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003007if (_return_value != Py_None) {
Larry Hastings78cf85c2014-01-04 12:44:57 -08003008 goto exit;
Serhiy Storchaka5dee6552016-06-09 16:16:06 +03003009}
Larry Hastings78cf85c2014-01-04 12:44:57 -08003010return_value = Py_None;
3011Py_INCREF(Py_None);
3012'''.strip())
3013
Larry Hastings4a55fc52014-01-12 11:09:57 -08003014class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07003015 type = 'int'
3016
3017 def render(self, function, data):
3018 self.declare(data)
3019 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003020 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07003021
3022class long_return_converter(CReturnConverter):
3023 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003024 conversion_fn = 'PyLong_FromLong'
3025 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003026 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003027
3028 def render(self, function, data):
3029 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003030 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07003031 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003032 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07003033
Larry Hastings4a55fc52014-01-12 11:09:57 -08003034class int_return_converter(long_return_converter):
3035 type = 'int'
3036 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07003037
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003038class init_return_converter(long_return_converter):
3039 """
3040 Special return converter for __init__ functions.
3041 """
3042 type = 'int'
3043 cast = '(long)'
3044
3045 def render(self, function, data):
3046 pass
3047
Larry Hastings4a55fc52014-01-12 11:09:57 -08003048class unsigned_long_return_converter(long_return_converter):
3049 type = 'unsigned long'
3050 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003051 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003052
3053class unsigned_int_return_converter(unsigned_long_return_converter):
3054 type = 'unsigned int'
3055 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003056 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003057
3058class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07003059 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003060 conversion_fn = 'PyLong_FromSsize_t'
3061
3062class size_t_return_converter(long_return_converter):
3063 type = 'size_t'
3064 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10003065 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08003066
3067
3068class double_return_converter(CReturnConverter):
3069 type = 'double'
3070 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07003071
3072 def render(self, function, data):
3073 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08003074 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07003075 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08003076 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
3077
3078class float_return_converter(double_return_converter):
3079 type = 'float'
3080 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07003081
3082
3083class DecodeFSDefault_return_converter(CReturnConverter):
3084 type = 'char *'
3085
3086 def render(self, function, data):
3087 self.declare(data)
3088 self.err_occurred_if_null_pointer("_return_value", data)
3089 data.return_conversion.append(
3090 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
3091
3092
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003093def eval_ast_expr(node, globals, *, filename='-'):
3094 """
3095 Takes an ast.Expr node. Compiles and evaluates it.
3096 Returns the result of the expression.
3097
3098 globals represents the globals dict the expression
3099 should see. (There's no equivalent for "locals" here.)
3100 """
3101
3102 if isinstance(node, ast.Expr):
3103 node = node.value
3104
3105 node = ast.Expression(node)
3106 co = compile(node, filename, 'eval')
3107 fn = types.FunctionType(co, globals)
3108 return fn()
3109
3110
Larry Hastings31826802013-10-19 00:09:25 -07003111class IndentStack:
3112 def __init__(self):
3113 self.indents = []
3114 self.margin = None
3115
3116 def _ensure(self):
3117 if not self.indents:
3118 fail('IndentStack expected indents, but none are defined.')
3119
3120 def measure(self, line):
3121 """
3122 Returns the length of the line's margin.
3123 """
3124 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003125 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07003126 stripped = line.lstrip()
3127 if not len(stripped):
3128 # we can't tell anything from an empty line
3129 # so just pretend it's indented like our current indent
3130 self._ensure()
3131 return self.indents[-1]
3132 return len(line) - len(stripped)
3133
3134 def infer(self, line):
3135 """
3136 Infer what is now the current margin based on this line.
3137 Returns:
3138 1 if we have indented (or this is the first margin)
3139 0 if the margin has not changed
3140 -N if we have dedented N times
3141 """
3142 indent = self.measure(line)
3143 margin = ' ' * indent
3144 if not self.indents:
3145 self.indents.append(indent)
3146 self.margin = margin
3147 return 1
3148 current = self.indents[-1]
3149 if indent == current:
3150 return 0
3151 if indent > current:
3152 self.indents.append(indent)
3153 self.margin = margin
3154 return 1
3155 # indent < current
3156 if indent not in self.indents:
3157 fail("Illegal outdent.")
3158 outdent_count = 0
3159 while indent != current:
3160 self.indents.pop()
3161 current = self.indents[-1]
3162 outdent_count -= 1
3163 self.margin = margin
3164 return outdent_count
3165
3166 @property
3167 def depth(self):
3168 """
3169 Returns how many margins are currently defined.
3170 """
3171 return len(self.indents)
3172
3173 def indent(self, line):
3174 """
3175 Indents a line by the currently defined margin.
3176 """
3177 return self.margin + line
3178
3179 def dedent(self, line):
3180 """
3181 Dedents a line by the currently defined margin.
3182 (The inverse of 'indent'.)
3183 """
3184 margin = self.margin
3185 indent = self.indents[-1]
3186 if not line.startswith(margin):
3187 fail('Cannot dedent, line does not start with the previous margin:')
3188 return line[indent:]
3189
3190
3191class DSLParser:
3192 def __init__(self, clinic):
3193 self.clinic = clinic
3194
3195 self.directives = {}
3196 for name in dir(self):
3197 # functions that start with directive_ are added to directives
3198 _, s, key = name.partition("directive_")
3199 if s:
3200 self.directives[key] = getattr(self, name)
3201
3202 # functions that start with at_ are too, with an @ in front
3203 _, s, key = name.partition("at_")
3204 if s:
3205 self.directives['@' + key] = getattr(self, name)
3206
3207 self.reset()
3208
3209 def reset(self):
3210 self.function = None
3211 self.state = self.state_dsl_start
3212 self.parameter_indent = None
3213 self.keyword_only = False
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003214 self.positional_only = False
Larry Hastings31826802013-10-19 00:09:25 -07003215 self.group = 0
3216 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003217 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003218 self.indent = IndentStack()
3219 self.kind = CALLABLE
3220 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003221 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003222 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003223
Larry Hastingsebdcb502013-11-23 14:54:00 -08003224 def directive_version(self, required):
3225 global version
3226 if version_comparitor(version, required) < 0:
3227 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3228
Larry Hastings31826802013-10-19 00:09:25 -07003229 def directive_module(self, name):
3230 fields = name.split('.')
3231 new = fields.pop()
3232 module, cls = self.clinic._module_and_class(fields)
3233 if cls:
3234 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003235
3236 if name in module.classes:
3237 fail("Already defined module " + repr(name) + "!")
3238
Larry Hastings31826802013-10-19 00:09:25 -07003239 m = Module(name, module)
3240 module.modules[name] = m
3241 self.block.signatures.append(m)
3242
Larry Hastingsc2047262014-01-25 20:43:29 -08003243 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003244 fields = name.split('.')
3245 in_classes = False
3246 parent = self
3247 name = fields.pop()
3248 so_far = []
3249 module, cls = self.clinic._module_and_class(fields)
3250
Larry Hastingsc2047262014-01-25 20:43:29 -08003251 parent = cls or module
3252 if name in parent.classes:
3253 fail("Already defined class " + repr(name) + "!")
3254
3255 c = Class(name, module, cls, typedef, type_object)
3256 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003257 self.block.signatures.append(c)
3258
Larry Hastingsbebf7352014-01-17 17:47:17 -08003259 def directive_set(self, name, value):
3260 if name not in ("line_prefix", "line_suffix"):
3261 fail("unknown variable", repr(name))
3262
3263 value = value.format_map({
3264 'block comment start': '/*',
3265 'block comment end': '*/',
3266 })
3267
3268 self.clinic.__dict__[name] = value
3269
3270 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003271 if command == 'new':
3272 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003273 return
3274
Zachary Ware071baa62014-01-21 23:07:12 -06003275 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003276 self.clinic.get_destination(name).clear()
3277 fail("unknown destination command", repr(command))
3278
3279
Larry Hastings0759f842015-04-03 13:09:02 -07003280 def directive_output(self, command_or_name, destination=''):
3281 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003282
Larry Hastings0759f842015-04-03 13:09:02 -07003283 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003284 preset = self.clinic.presets.get(destination)
3285 if not preset:
3286 fail("Unknown preset " + repr(destination) + "!")
3287 fd.update(preset)
3288 return
3289
Larry Hastings0759f842015-04-03 13:09:02 -07003290 if command_or_name == "push":
3291 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003292 return
3293
Larry Hastings0759f842015-04-03 13:09:02 -07003294 if command_or_name == "pop":
3295 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003296 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003297 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003298 fd.update(previous_fd)
3299 return
3300
3301 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003302 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003303 self.block.output.append(pprint.pformat(fd))
3304 self.block.output.append('\n')
3305 return
3306
3307 d = self.clinic.get_destination(destination)
3308
Larry Hastings0759f842015-04-03 13:09:02 -07003309 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003310 for name in list(fd):
3311 fd[name] = d
3312 return
3313
Larry Hastings0759f842015-04-03 13:09:02 -07003314 if command_or_name not in fd:
3315 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3316 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003317
3318 def directive_dump(self, name):
3319 self.block.output.append(self.clinic.get_destination(name).dump())
3320
3321 def directive_print(self, *args):
3322 self.block.output.append(' '.join(args))
3323 self.block.output.append('\n')
3324
3325 def directive_preserve(self):
3326 if self.preserve_output:
3327 fail("Can't have preserve twice in one block!")
3328 self.preserve_output = True
3329
Larry Hastings31826802013-10-19 00:09:25 -07003330 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003331 if self.kind is not CALLABLE:
3332 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003333 self.kind = CLASS_METHOD
3334
3335 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003336 if self.kind is not CALLABLE:
3337 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003338 self.kind = STATIC_METHOD
3339
3340 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003341 if self.coexist:
3342 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003343 self.coexist = True
3344
3345 def parse(self, block):
3346 self.reset()
3347 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003348 self.saved_output = self.block.output
3349 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003350 block_start = self.clinic.block_parser.line_number
3351 lines = block.input.split('\n')
3352 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3353 if '\t' in line:
3354 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3355 self.state(line)
3356
3357 self.next(self.state_terminal)
3358 self.state(None)
3359
Larry Hastingsbebf7352014-01-17 17:47:17 -08003360 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3361
3362 if self.preserve_output:
3363 if block.output:
3364 fail("'preserve' only works for blocks that don't produce any output!")
3365 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003366
3367 @staticmethod
3368 def ignore_line(line):
3369 # ignore comment-only lines
3370 if line.lstrip().startswith('#'):
3371 return True
3372
3373 # Ignore empty lines too
3374 # (but not in docstring sections!)
3375 if not line.strip():
3376 return True
3377
3378 return False
3379
3380 @staticmethod
3381 def calculate_indent(line):
3382 return len(line) - len(line.strip())
3383
3384 def next(self, state, line=None):
3385 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3386 self.state = state
3387 if line is not None:
3388 self.state(line)
3389
3390 def state_dsl_start(self, line):
3391 # self.block = self.ClinicOutputBlock(self)
3392 if self.ignore_line(line):
3393 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003394
3395 # is it a directive?
3396 fields = shlex.split(line)
3397 directive_name = fields[0]
3398 directive = self.directives.get(directive_name, None)
3399 if directive:
3400 try:
3401 directive(*fields[1:])
3402 except TypeError as e:
3403 fail(str(e))
3404 return
3405
Larry Hastings31826802013-10-19 00:09:25 -07003406 self.next(self.state_modulename_name, line)
3407
3408 def state_modulename_name(self, line):
3409 # looking for declaration, which establishes the leftmost column
3410 # line should be
3411 # modulename.fnname [as c_basename] [-> return annotation]
3412 # square brackets denote optional syntax.
3413 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003414 # alternatively:
3415 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3416 # clones the parameters and return converter from that
3417 # function. you can't modify them. you must enter a
3418 # new docstring.
3419 #
Larry Hastings31826802013-10-19 00:09:25 -07003420 # (but we might find a directive first!)
3421 #
3422 # this line is permitted to start with whitespace.
3423 # we'll call this number of spaces F (for "function").
3424
3425 if not line.strip():
3426 return
3427
3428 self.indent.infer(line)
3429
Larry Hastings4a714d42014-01-14 22:22:41 -08003430 # are we cloning?
3431 before, equals, existing = line.rpartition('=')
3432 if equals:
3433 full_name, _, c_basename = before.partition(' as ')
3434 full_name = full_name.strip()
3435 c_basename = c_basename.strip()
3436 existing = existing.strip()
3437 if (is_legal_py_identifier(full_name) and
3438 (not c_basename or is_legal_c_identifier(c_basename)) and
3439 is_legal_py_identifier(existing)):
3440 # we're cloning!
3441 fields = [x.strip() for x in existing.split('.')]
3442 function_name = fields.pop()
3443 module, cls = self.clinic._module_and_class(fields)
3444
3445 for existing_function in (cls or module).functions:
3446 if existing_function.name == function_name:
3447 break
3448 else:
3449 existing_function = None
3450 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003451 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003452 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003453 fail("Couldn't find existing function " + repr(existing) + "!")
3454
3455 fields = [x.strip() for x in full_name.split('.')]
3456 function_name = fields.pop()
3457 module, cls = self.clinic._module_and_class(fields)
3458
3459 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3460 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003461 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 -08003462
3463 self.block.signatures.append(self.function)
3464 (cls or module).functions.append(self.function)
3465 self.next(self.state_function_docstring)
3466 return
3467
Larry Hastings31826802013-10-19 00:09:25 -07003468 line, _, returns = line.partition('->')
3469
3470 full_name, _, c_basename = line.partition(' as ')
3471 full_name = full_name.strip()
3472 c_basename = c_basename.strip() or None
3473
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003474 if not is_legal_py_identifier(full_name):
3475 fail("Illegal function name: {}".format(full_name))
3476 if c_basename and not is_legal_c_identifier(c_basename):
3477 fail("Illegal C basename: {}".format(c_basename))
3478
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003479 return_converter = None
3480 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003481 ast_input = "def x() -> {}: pass".format(returns)
3482 module = None
3483 try:
3484 module = ast.parse(ast_input)
3485 except SyntaxError:
3486 pass
3487 if not module:
3488 fail("Badly-formed annotation for " + full_name + ": " + returns)
3489 try:
3490 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003491 if legacy:
3492 fail("Legacy converter {!r} not allowed as a return converter"
3493 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003494 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003495 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003496 return_converter = return_converters[name](**kwargs)
3497 except ValueError:
3498 fail("Badly-formed annotation for " + full_name + ": " + returns)
3499
3500 fields = [x.strip() for x in full_name.split('.')]
3501 function_name = fields.pop()
3502 module, cls = self.clinic._module_and_class(fields)
3503
Larry Hastings8666e652014-01-12 14:12:59 -08003504 fields = full_name.split('.')
3505 if fields[-1] == '__new__':
3506 if (self.kind != CLASS_METHOD) or (not cls):
3507 fail("__new__ must be a class method!")
3508 self.kind = METHOD_NEW
3509 elif fields[-1] == '__init__':
3510 if (self.kind != CALLABLE) or (not cls):
3511 fail("__init__ must be a normal method, not a class or static method!")
3512 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003513 if not return_converter:
3514 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003515 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003516 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003517
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003518 if not return_converter:
3519 return_converter = CReturnConverter()
3520
Larry Hastings31826802013-10-19 00:09:25 -07003521 if not module:
3522 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3523 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3524 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3525 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003526
3527 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003528 type, name = correct_name_for_self(self.function)
3529 kwargs = {}
3530 if cls and type == "PyObject *":
3531 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08003532 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003533 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3534 self.function.parameters[sc.name] = p_self
3535
Larry Hastings4a714d42014-01-14 22:22:41 -08003536 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003537 self.next(self.state_parameters_start)
3538
3539 # Now entering the parameters section. The rules, formally stated:
3540 #
3541 # * All lines must be indented with spaces only.
3542 # * The first line must be a parameter declaration.
3543 # * The first line must be indented.
3544 # * This first line establishes the indent for parameters.
3545 # * We'll call this number of spaces P (for "parameter").
3546 # * Thenceforth:
3547 # * Lines indented with P spaces specify a parameter.
3548 # * Lines indented with > P spaces are docstrings for the previous
3549 # parameter.
3550 # * We'll call this number of spaces D (for "docstring").
3551 # * All subsequent lines indented with >= D spaces are stored as
3552 # part of the per-parameter docstring.
3553 # * All lines will have the first D spaces of the indent stripped
3554 # before they are stored.
3555 # * It's illegal to have a line starting with a number of spaces X
3556 # such that P < X < D.
3557 # * A line with < P spaces is the first line of the function
3558 # docstring, which ends processing for parameters and per-parameter
3559 # docstrings.
3560 # * The first line of the function docstring must be at the same
3561 # indent as the function declaration.
3562 # * It's illegal to have any line in the parameters section starting
3563 # with X spaces such that F < X < P. (As before, F is the indent
3564 # of the function declaration.)
3565 #
Larry Hastings31826802013-10-19 00:09:25 -07003566 # Also, currently Argument Clinic places the following restrictions on groups:
3567 # * Each group must contain at least one parameter.
3568 # * Each group may contain at most one group, which must be the furthest
3569 # thing in the group from the required parameters. (The nested group
3570 # must be the first in the group when it's before the required
3571 # parameters, and the last thing in the group when after the required
3572 # parameters.)
3573 # * There may be at most one (top-level) group to the left or right of
3574 # the required parameters.
3575 # * You must specify a slash, and it must be after all parameters.
3576 # (In other words: either all parameters are positional-only,
3577 # or none are.)
3578 #
3579 # Said another way:
3580 # * Each group must contain at least one parameter.
3581 # * All left square brackets before the required parameters must be
3582 # consecutive. (You can't have a left square bracket followed
3583 # by a parameter, then another left square bracket. You can't
3584 # have a left square bracket, a parameter, a right square bracket,
3585 # and then a left square bracket.)
3586 # * All right square brackets after the required parameters must be
3587 # consecutive.
3588 #
3589 # These rules are enforced with a single state variable:
3590 # "parameter_state". (Previously the code was a miasma of ifs and
3591 # separate boolean state variables.) The states are:
3592 #
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003593 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
3594 # 01 2 3 4 5 6 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003595 #
3596 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3597 # 1: ps_left_square_before. left square brackets before required parameters.
3598 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003599 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3600 # (we don't know yet). (renumber left groups!)
3601 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3602 # now must have default values.
3603 # 5: ps_group_after. in a group, after required parameters.
3604 # 6: ps_right_square_after. right square brackets after required parameters.
Larry Hastings31826802013-10-19 00:09:25 -07003605 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003606 ps_optional, ps_group_after, ps_right_square_after = range(7)
Larry Hastings31826802013-10-19 00:09:25 -07003607
3608 def state_parameters_start(self, line):
3609 if self.ignore_line(line):
3610 return
3611
3612 # if this line is not indented, we have no parameters
3613 if not self.indent.infer(line):
3614 return self.next(self.state_function_docstring, line)
3615
Larry Hastings2a727912014-01-16 11:32:01 -08003616 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003617 return self.next(self.state_parameter, line)
3618
3619
3620 def to_required(self):
3621 """
3622 Transition to the "required" parameter state.
3623 """
3624 if self.parameter_state != self.ps_required:
3625 self.parameter_state = self.ps_required
3626 for p in self.function.parameters.values():
3627 p.group = -p.group
3628
3629 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003630 if self.parameter_continuation:
3631 line = self.parameter_continuation + ' ' + line.lstrip()
3632 self.parameter_continuation = ''
3633
Larry Hastings31826802013-10-19 00:09:25 -07003634 if self.ignore_line(line):
3635 return
3636
3637 assert self.indent.depth == 2
3638 indent = self.indent.infer(line)
3639 if indent == -1:
3640 # we outdented, must be to definition column
3641 return self.next(self.state_function_docstring, line)
3642
3643 if indent == 1:
3644 # we indented, must be to new parameter docstring column
3645 return self.next(self.state_parameter_docstring_start, line)
3646
Larry Hastings2a727912014-01-16 11:32:01 -08003647 line = line.rstrip()
3648 if line.endswith('\\'):
3649 self.parameter_continuation = line[:-1]
3650 return
3651
Larry Hastings31826802013-10-19 00:09:25 -07003652 line = line.lstrip()
3653
3654 if line in ('*', '/', '[', ']'):
3655 self.parse_special_symbol(line)
3656 return
3657
3658 if self.parameter_state in (self.ps_start, self.ps_required):
3659 self.to_required()
3660 elif self.parameter_state == self.ps_left_square_before:
3661 self.parameter_state = self.ps_group_before
3662 elif self.parameter_state == self.ps_group_before:
3663 if not self.group:
3664 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003665 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003666 pass
3667 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003668 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003669
Larry Hastings7726ac92014-01-31 22:03:12 -08003670 # handle "as" for parameters too
3671 c_name = None
3672 name, have_as_token, trailing = line.partition(' as ')
3673 if have_as_token:
3674 name = name.strip()
3675 if ' ' not in name:
3676 fields = trailing.strip().split(' ')
3677 if not fields:
3678 fail("Invalid 'as' clause!")
3679 c_name = fields[0]
3680 if c_name.endswith(':'):
3681 name += ':'
3682 c_name = c_name[:-1]
3683 fields[0] = name
3684 line = ' '.join(fields)
3685
Larry Hastings2a727912014-01-16 11:32:01 -08003686 base, equals, default = line.rpartition('=')
3687 if not equals:
3688 base = default
3689 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003690
Larry Hastings31826802013-10-19 00:09:25 -07003691 module = None
3692 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003693 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003694 module = ast.parse(ast_input)
3695 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003696 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003697 # the last = was probably inside a function call, like
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003698 # c: int(accept={str})
Larry Hastingsc2047262014-01-25 20:43:29 -08003699 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003700 default = None
3701 ast_input = "def x({}): pass".format(line)
3702 module = ast.parse(ast_input)
3703 except SyntaxError:
3704 pass
Larry Hastings31826802013-10-19 00:09:25 -07003705 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003706 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003707
3708 function_args = module.body[0].args
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003709
3710 if len(function_args.args) > 1:
3711 fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line)
3712 if function_args.defaults or function_args.kw_defaults:
3713 fail("Function " + self.function.name + " has an invalid parameter declaration (default value?):\n\t" + line)
3714 if function_args.vararg or function_args.kwarg:
3715 fail("Function " + self.function.name + " has an invalid parameter declaration (*args? **kwargs?):\n\t" + line)
3716
Larry Hastings31826802013-10-19 00:09:25 -07003717 parameter = function_args.args[0]
3718
Larry Hastings16c51912014-01-07 11:53:01 -08003719 parameter_name = parameter.arg
3720 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3721
Larry Hastings2a727912014-01-16 11:32:01 -08003722 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003723 if self.parameter_state == self.ps_optional:
3724 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 -08003725 value = unspecified
3726 if 'py_default' in kwargs:
3727 fail("You can't specify py_default without specifying a default value!")
3728 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003729 if self.parameter_state == self.ps_required:
3730 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003731 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003732 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003733 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003734 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003735 try:
3736 module = ast.parse(ast_input)
3737
Larry Hastings5c661892014-01-24 06:17:25 -08003738 if 'c_default' not in kwargs:
3739 # we can only represent very simple data values in C.
3740 # detect whether default is okay, via a blacklist
3741 # of disallowed ast nodes.
3742 class DetectBadNodes(ast.NodeVisitor):
3743 bad = False
3744 def bad_node(self, node):
3745 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003746
Larry Hastings5c661892014-01-24 06:17:25 -08003747 # inline function call
3748 visit_Call = bad_node
3749 # inline if statement ("x = 3 if y else z")
3750 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003751
Larry Hastings5c661892014-01-24 06:17:25 -08003752 # comprehensions and generator expressions
3753 visit_ListComp = visit_SetComp = bad_node
3754 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003755
Larry Hastings5c661892014-01-24 06:17:25 -08003756 # literals for advanced types
3757 visit_Dict = visit_Set = bad_node
3758 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003759
Larry Hastings5c661892014-01-24 06:17:25 -08003760 # "starred": "a = [1, 2, 3]; *a"
3761 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003762
Larry Hastings5c661892014-01-24 06:17:25 -08003763 # allow ellipsis, for now
3764 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003765
Larry Hastings5c661892014-01-24 06:17:25 -08003766 blacklist = DetectBadNodes()
3767 blacklist.visit(module)
3768 bad = blacklist.bad
3769 else:
3770 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003771 # but at least make an attempt at ensuring it's a valid expression.
3772 try:
3773 value = eval(default)
3774 if value == unspecified:
3775 fail("'unspecified' is not a legal default value!")
3776 except NameError:
3777 pass # probably a named constant
3778 except Exception as e:
3779 fail("Malformed expression given as default value\n"
3780 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003781 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003782 fail("Unsupported expression as default value: " + repr(default))
3783
3784 expr = module.body[0].value
3785 # mild hack: explicitly support NULL as a default value
3786 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3787 value = NULL
3788 py_default = 'None'
3789 c_default = "NULL"
3790 elif (isinstance(expr, ast.BinOp) or
3791 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3792 c_default = kwargs.get("c_default")
3793 if not (isinstance(c_default, str) and c_default):
3794 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3795 py_default = default
3796 value = unknown
3797 elif isinstance(expr, ast.Attribute):
3798 a = []
3799 n = expr
3800 while isinstance(n, ast.Attribute):
3801 a.append(n.attr)
3802 n = n.value
3803 if not isinstance(n, ast.Name):
3804 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3805 a.append(n.id)
3806 py_default = ".".join(reversed(a))
3807
3808 c_default = kwargs.get("c_default")
3809 if not (isinstance(c_default, str) and c_default):
3810 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3811
3812 try:
3813 value = eval(py_default)
3814 except NameError:
3815 value = unknown
3816 else:
3817 value = ast.literal_eval(expr)
3818 py_default = repr(value)
3819 if isinstance(value, (bool, None.__class__)):
3820 c_default = "Py_" + py_default
3821 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003822 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003823 else:
3824 c_default = py_default
3825
3826 except SyntaxError as e:
3827 fail("Syntax error: " + repr(e.text))
3828 except (ValueError, AttributeError):
3829 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003830 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003831 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003832 if not (isinstance(c_default, str) and c_default):
3833 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3834
Larry Hastings2a727912014-01-16 11:32:01 -08003835 kwargs.setdefault('c_default', c_default)
3836 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003837
Larry Hastings31826802013-10-19 00:09:25 -07003838 dict = legacy_converters if legacy else converters
3839 legacy_str = "legacy " if legacy else ""
3840 if name not in dict:
3841 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08003842 # if you use a c_name for the parameter, we just give that name to the converter
3843 # but the parameter object gets the python name
3844 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07003845
3846 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003847
3848 if isinstance(converter, self_converter):
3849 if len(self.function.parameters) == 1:
3850 if (self.parameter_state != self.ps_required):
3851 fail("A 'self' parameter cannot be marked optional.")
3852 if value is not unspecified:
3853 fail("A 'self' parameter cannot have a default value.")
3854 if self.group:
3855 fail("A 'self' parameter cannot be in an optional group.")
3856 kind = inspect.Parameter.POSITIONAL_ONLY
3857 self.parameter_state = self.ps_start
3858 self.function.parameters.clear()
3859 else:
3860 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3861
Larry Hastings31826802013-10-19 00:09:25 -07003862 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003863
3864 if parameter_name in self.function.parameters:
3865 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003866 self.function.parameters[parameter_name] = p
3867
3868 def parse_converter(self, annotation):
3869 if isinstance(annotation, ast.Str):
3870 return annotation.s, True, {}
3871
3872 if isinstance(annotation, ast.Name):
3873 return annotation.id, False, {}
3874
Larry Hastings4a55fc52014-01-12 11:09:57 -08003875 if not isinstance(annotation, ast.Call):
3876 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003877
3878 name = annotation.func.id
Larry Hastingsdbfdc382015-05-04 06:59:46 -07003879 symbols = globals()
3880
3881 kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords}
Larry Hastings31826802013-10-19 00:09:25 -07003882 return name, False, kwargs
3883
3884 def parse_special_symbol(self, symbol):
Larry Hastings31826802013-10-19 00:09:25 -07003885 if symbol == '*':
3886 if self.keyword_only:
3887 fail("Function " + self.function.name + " uses '*' more than once.")
3888 self.keyword_only = True
3889 elif symbol == '[':
3890 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3891 self.parameter_state = self.ps_left_square_before
3892 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3893 self.parameter_state = self.ps_group_after
3894 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003895 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003896 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08003897 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07003898 elif symbol == ']':
3899 if not self.group:
3900 fail("Function " + self.function.name + " has a ] without a matching [.")
3901 if not any(p.group == self.group for p in self.function.parameters.values()):
3902 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3903 self.group -= 1
3904 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3905 self.parameter_state = self.ps_group_before
3906 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3907 self.parameter_state = self.ps_right_square_after
3908 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003909 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003910 elif symbol == '/':
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03003911 if self.positional_only:
3912 fail("Function " + self.function.name + " uses '/' more than once.")
3913 self.positional_only = True
Larry Hastingsc2047262014-01-25 20:43:29 -08003914 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003915 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003916 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3917 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003918 if self.keyword_only:
3919 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
Berker Peksagf23530f2014-10-19 18:04:38 +03003920 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07003921 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08003922 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07003923 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3924 p.kind = inspect.Parameter.POSITIONAL_ONLY
3925
3926 def state_parameter_docstring_start(self, line):
3927 self.parameter_docstring_indent = len(self.indent.margin)
3928 assert self.indent.depth == 3
3929 return self.next(self.state_parameter_docstring, line)
3930
3931 # every line of the docstring must start with at least F spaces,
3932 # where F > P.
3933 # these F spaces will be stripped.
3934 def state_parameter_docstring(self, line):
3935 stripped = line.strip()
3936 if stripped.startswith('#'):
3937 return
3938
3939 indent = self.indent.measure(line)
3940 if indent < self.parameter_docstring_indent:
3941 self.indent.infer(line)
3942 assert self.indent.depth < 3
3943 if self.indent.depth == 2:
3944 # back to a parameter
3945 return self.next(self.state_parameter, line)
3946 assert self.indent.depth == 1
3947 return self.next(self.state_function_docstring, line)
3948
3949 assert self.function.parameters
3950 last_parameter = next(reversed(list(self.function.parameters.values())))
3951
3952 new_docstring = last_parameter.docstring
3953
3954 if new_docstring:
3955 new_docstring += '\n'
3956 if stripped:
3957 new_docstring += self.indent.dedent(line)
3958
3959 last_parameter.docstring = new_docstring
3960
3961 # the final stanza of the DSL is the docstring.
3962 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003963 if self.group:
3964 fail("Function " + self.function.name + " has a ] without a matching [.")
3965
3966 stripped = line.strip()
3967 if stripped.startswith('#'):
3968 return
3969
3970 new_docstring = self.function.docstring
3971 if new_docstring:
3972 new_docstring += "\n"
3973 if stripped:
3974 line = self.indent.dedent(line).rstrip()
3975 else:
3976 line = ''
3977 new_docstring += line
3978 self.function.docstring = new_docstring
3979
3980 def format_docstring(self):
3981 f = self.function
3982
Larry Hastings5c661892014-01-24 06:17:25 -08003983 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
3984 if new_or_init and not f.docstring:
3985 # don't render a docstring at all, no signature, nothing.
3986 return f.docstring
3987
Larry Hastings2623c8c2014-02-08 22:15:29 -08003988 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08003989 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07003990
3991 ##
3992 ## docstring first line
3993 ##
3994
Larry Hastings2623c8c2014-02-08 22:15:29 -08003995 if new_or_init:
3996 # classes get *just* the name of the class
3997 # not __new__, not __init__, and not module.classname
3998 assert f.cls
3999 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08004000 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08004001 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07004002 add('(')
4003
4004 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08004005 assert parameters, "We should always have a self parameter. " + repr(f)
4006 assert isinstance(parameters[0].converter, self_converter)
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004007 # self is always positional-only.
4008 assert parameters[0].is_positional_only()
Larry Hastings5c661892014-01-24 06:17:25 -08004009 parameters[0].right_bracket_count = 0
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004010 positional_only = True
4011 for p in parameters[1:]:
4012 if not p.is_positional_only():
4013 positional_only = False
4014 else:
4015 assert positional_only
4016 if positional_only:
4017 p.right_bracket_count = abs(p.group)
Larry Hastings31826802013-10-19 00:09:25 -07004018 else:
4019 # don't put any right brackets around non-positional-only parameters, ever.
Serhiy Storchakaf41b82f2016-06-09 16:30:29 +03004020 p.right_bracket_count = 0
Larry Hastings31826802013-10-19 00:09:25 -07004021
4022 right_bracket_count = 0
4023
4024 def fix_right_bracket_count(desired):
4025 nonlocal right_bracket_count
4026 s = ''
4027 while right_bracket_count < desired:
4028 s += '['
4029 right_bracket_count += 1
4030 while right_bracket_count > desired:
4031 s += ']'
4032 right_bracket_count -= 1
4033 return s
4034
Larry Hastings2623c8c2014-02-08 22:15:29 -08004035 need_slash = False
4036 added_slash = False
4037 need_a_trailing_slash = False
4038
4039 # we only need a trailing slash:
4040 # * if this is not a "docstring_only" signature
4041 # * and if the last *shown* parameter is
4042 # positional only
4043 if not f.docstring_only:
4044 for p in reversed(parameters):
4045 if not p.converter.show_in_signature:
4046 continue
4047 if p.is_positional_only():
4048 need_a_trailing_slash = True
4049 break
4050
4051
Larry Hastings31826802013-10-19 00:09:25 -07004052 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08004053
4054 first_parameter = True
4055 last_p = parameters[-1]
4056 line_length = len(''.join(text))
4057 indent = " " * line_length
4058 def add_parameter(text):
4059 nonlocal line_length
4060 nonlocal first_parameter
4061 if first_parameter:
4062 s = text
4063 first_parameter = False
4064 else:
4065 s = ' ' + text
4066 if line_length + len(s) >= 72:
4067 add('\n')
4068 add(indent)
4069 line_length = len(indent)
4070 s = text
4071 line_length += len(s)
4072 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07004073
4074 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08004075 if not p.converter.show_in_signature:
4076 continue
Larry Hastings31826802013-10-19 00:09:25 -07004077 assert p.name
4078
Larry Hastings2623c8c2014-02-08 22:15:29 -08004079 is_self = isinstance(p.converter, self_converter)
4080 if is_self and f.docstring_only:
4081 # this isn't a real machine-parsable signature,
4082 # so let's not print the "self" parameter
4083 continue
4084
4085 if p.is_positional_only():
4086 need_slash = not f.docstring_only
4087 elif need_slash and not (added_slash or p.is_positional_only()):
4088 added_slash = True
4089 add_parameter('/,')
4090
Larry Hastings31826802013-10-19 00:09:25 -07004091 if p.is_keyword_only() and not added_star:
4092 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08004093 add_parameter('*,')
4094
4095 p_add, p_output = text_accumulator()
4096 p_add(fix_right_bracket_count(p.right_bracket_count))
4097
4098 if isinstance(p.converter, self_converter):
4099 # annotate first parameter as being a "self".
4100 #
4101 # if inspect.Signature gets this function,
4102 # and it's already bound, the self parameter
4103 # will be stripped off.
4104 #
4105 # if it's not bound, it should be marked
4106 # as positional-only.
4107 #
4108 # note: we don't print "self" for __init__,
4109 # because this isn't actually the signature
4110 # for __init__. (it can't be, __init__ doesn't
4111 # have a docstring.) if this is an __init__
4112 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03004113 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08004114 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07004115
Larry Hastings5c661892014-01-24 06:17:25 -08004116 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08004117 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08004118
Larry Hastings31826802013-10-19 00:09:25 -07004119 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08004120 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08004121 value = p.converter.py_default
4122 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08004123 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08004124 p_add(value)
4125
4126 if (p != last_p) or need_a_trailing_slash:
4127 p_add(',')
4128
4129 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07004130
4131 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08004132 if need_a_trailing_slash:
4133 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07004134 add(')')
4135
Larry Hastings2a727912014-01-16 11:32:01 -08004136 # PEP 8 says:
4137 #
4138 # The Python standard library will not use function annotations
4139 # as that would result in a premature commitment to a particular
4140 # annotation style. Instead, the annotations are left for users
4141 # to discover and experiment with useful annotation styles.
4142 #
4143 # therefore this is commented out:
4144 #
4145 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004146 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08004147 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004148
Larry Hastings2623c8c2014-02-08 22:15:29 -08004149 if not f.docstring_only:
Zachary Ware8ef887c2015-04-13 18:22:35 -05004150 add("\n" + sig_end_marker + "\n")
Larry Hastings2623c8c2014-02-08 22:15:29 -08004151
Larry Hastings31826802013-10-19 00:09:25 -07004152 docstring_first_line = output()
4153
4154 # now fix up the places where the brackets look wrong
4155 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4156
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004157 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004158 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004159 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004160 for p in parameters:
4161 if not p.docstring.strip():
4162 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004163 if spacer_line:
4164 add('\n')
4165 else:
4166 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004167 add(" ")
4168 add(p.name)
4169 add('\n')
4170 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004171 parameters = output()
4172 if parameters:
4173 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004174
4175 ##
4176 ## docstring body
4177 ##
4178
4179 docstring = f.docstring.rstrip()
4180 lines = [line.rstrip() for line in docstring.split('\n')]
4181
4182 # Enforce the summary line!
4183 # The first line of a docstring should be a summary of the function.
4184 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4185 # by itself.
4186 #
4187 # Argument Clinic enforces the following rule:
4188 # * either the docstring is empty,
4189 # * or it must have a summary line.
4190 #
4191 # Guido said Clinic should enforce this:
4192 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4193
4194 if len(lines) >= 2:
4195 if lines[1]:
4196 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4197 "Every non-blank function docstring must start with\n" +
4198 "a single line summary followed by an empty line.")
4199 elif len(lines) == 1:
4200 # the docstring is only one line right now--the summary line.
4201 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004202 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004203 lines.append('')
4204
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004205 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4206 if parameters_marker_count > 1:
4207 fail('You may not specify {parameters} more than once in a docstring!')
4208
4209 if not parameters_marker_count:
4210 # insert after summary line
4211 lines.insert(2, '{parameters}')
4212
4213 # insert at front of docstring
4214 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004215
4216 docstring = "\n".join(lines)
4217
4218 add(docstring)
4219 docstring = output()
4220
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004221 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004222 docstring = docstring.rstrip()
4223
4224 return docstring
4225
4226 def state_terminal(self, line):
4227 """
4228 Called when processing the block is done.
4229 """
4230 assert not line
4231
4232 if not self.function:
4233 return
4234
4235 if self.keyword_only:
4236 values = self.function.parameters.values()
4237 if not values:
4238 no_parameter_after_star = True
4239 else:
4240 last_parameter = next(reversed(list(values)))
4241 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4242 if no_parameter_after_star:
4243 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4244
4245 # remove trailing whitespace from all parameter docstrings
4246 for name, value in self.function.parameters.items():
4247 if not value:
4248 continue
4249 value.docstring = value.docstring.rstrip()
4250
4251 self.function.docstring = self.format_docstring()
4252
4253
Larry Hastings5c661892014-01-24 06:17:25 -08004254
4255
Larry Hastings31826802013-10-19 00:09:25 -07004256# maps strings to callables.
4257# the callable should return an object
4258# that implements the clinic parser
4259# interface (__init__ and parse).
4260#
4261# example parsers:
4262# "clinic", handles the Clinic DSL
4263# "python", handles running Python code
4264#
4265parsers = {'clinic' : DSLParser, 'python': PythonParser}
4266
4267
4268clinic = None
4269
4270
4271def main(argv):
4272 import sys
4273
4274 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4275 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4276
4277 import argparse
4278 cmdline = argparse.ArgumentParser()
4279 cmdline.add_argument("-f", "--force", action='store_true')
4280 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004281 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004282 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004283 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004284 cmdline.add_argument("filename", type=str, nargs="*")
4285 ns = cmdline.parse_args(argv)
4286
4287 if ns.converters:
4288 if ns.filename:
4289 print("Usage error: can't specify --converters and a filename at the same time.")
4290 print()
4291 cmdline.print_usage()
4292 sys.exit(-1)
4293 converters = []
4294 return_converters = []
4295 ignored = set("""
4296 add_c_converter
4297 add_c_return_converter
4298 add_default_legacy_c_converter
4299 add_legacy_c_converter
4300 """.strip().split())
4301 module = globals()
4302 for name in module:
4303 for suffix, ids in (
4304 ("_return_converter", return_converters),
4305 ("_converter", converters),
4306 ):
4307 if name in ignored:
4308 continue
4309 if name.endswith(suffix):
4310 ids.append((name, name[:-len(suffix)]))
4311 break
4312 print()
4313
4314 print("Legacy converters:")
4315 legacy = sorted(legacy_converters)
4316 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4317 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4318 print()
4319
4320 for title, attribute, ids in (
4321 ("Converters", 'converter_init', converters),
4322 ("Return converters", 'return_converter_init', return_converters),
4323 ):
4324 print(title + ":")
4325 longest = -1
4326 for name, short_name in ids:
4327 longest = max(longest, len(short_name))
4328 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4329 cls = module[name]
4330 callable = getattr(cls, attribute, None)
4331 if not callable:
4332 continue
4333 signature = inspect.signature(callable)
4334 parameters = []
4335 for parameter_name, parameter in signature.parameters.items():
4336 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4337 if parameter.default != inspect.Parameter.empty:
4338 s = '{}={!r}'.format(parameter_name, parameter.default)
4339 else:
4340 s = parameter_name
4341 parameters.append(s)
4342 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004343 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004344 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4345 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004346 sys.exit(0)
4347
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004348 if ns.make:
4349 if ns.output or ns.filename:
4350 print("Usage error: can't use -o or filenames with --make.")
4351 print()
4352 cmdline.print_usage()
4353 sys.exit(-1)
4354 for root, dirs, files in os.walk('.'):
Zachary Warebbbbe7e2015-04-13 18:33:41 -05004355 for rcs_dir in ('.svn', '.git', '.hg', 'build', 'externals'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004356 if rcs_dir in dirs:
4357 dirs.remove(rcs_dir)
4358 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004359 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004360 continue
4361 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004362 if ns.verbose:
4363 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004364 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004365 return
4366
Larry Hastings31826802013-10-19 00:09:25 -07004367 if not ns.filename:
4368 cmdline.print_usage()
4369 sys.exit(-1)
4370
4371 if ns.output and len(ns.filename) > 1:
4372 print("Usage error: can't use -o with multiple filenames.")
4373 print()
4374 cmdline.print_usage()
4375 sys.exit(-1)
4376
4377 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004378 if ns.verbose:
4379 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004380 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004381
4382
4383if __name__ == "__main__":
4384 sys.exit(main(sys.argv[1:]))