blob: 6432951e07f7bdc81680daa7245f32e0a706d9c6 [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 Hastingsbebf7352014-01-17 17:47:17 -080029import uuid
Larry Hastings31826802013-10-19 00:09:25 -070030
Larry Hastings31826802013-10-19 00:09:25 -070031# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070032#
33# soon:
34#
35# * allow mixing any two of {positional-only, positional-or-keyword,
36# keyword-only}
37# * dict constructor uses positional-only and keyword-only
38# * max and min use positional only with an optional group
39# and keyword-only
40#
Larry Hastings31826802013-10-19 00:09:25 -070041
Larry Hastingsebdcb502013-11-23 14:54:00 -080042version = '1'
43
Larry Hastings31826802013-10-19 00:09:25 -070044_empty = inspect._empty
45_void = inspect._void
46
Larry Hastings4a55fc52014-01-12 11:09:57 -080047NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070048
49class Unspecified:
50 def __repr__(self):
51 return '<Unspecified>'
52
53unspecified = Unspecified()
54
55
56class Null:
57 def __repr__(self):
58 return '<Null>'
59
60NULL = Null()
61
62
Larry Hastings2a727912014-01-16 11:32:01 -080063class Unknown:
64 def __repr__(self):
65 return '<Unknown>'
66
67unknown = Unknown()
68
69
Larry Hastings0759f842015-04-03 13:09:02 -070070_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output")
71
Larry Hastings31826802013-10-19 00:09:25 -070072def _text_accumulator():
73 text = []
74 def output():
75 s = ''.join(text)
76 text.clear()
77 return s
Larry Hastings0759f842015-04-03 13:09:02 -070078 return _text_accumulator_nt(text, text.append, output)
Larry Hastings31826802013-10-19 00:09:25 -070079
80
Larry Hastings0759f842015-04-03 13:09:02 -070081text_accumulator_nt = collections.namedtuple("text_accumulator", "text append")
82
Larry Hastings31826802013-10-19 00:09:25 -070083def text_accumulator():
84 """
85 Creates a simple text accumulator / joiner.
86
87 Returns a pair of callables:
88 append, output
89 "append" appends a string to the accumulator.
90 "output" returns the contents of the accumulator
91 joined together (''.join(accumulator)) and
92 empties the accumulator.
93 """
94 text, append, output = _text_accumulator()
Larry Hastings0759f842015-04-03 13:09:02 -070095 return text_accumulator_nt(append, output)
Larry Hastings31826802013-10-19 00:09:25 -070096
97
Larry Hastingsbebf7352014-01-17 17:47:17 -080098def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -070099 joined = " ".join([str(a) for a in args])
100 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800101 if fail:
102 add("Error")
103 else:
104 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -0700105 if clinic:
106 if filename is None:
107 filename = clinic.filename
Larry Hastings581ee362014-01-28 05:00:08 -0800108 if getattr(clinic, 'block_parser', None) and (line_number is None):
Larry Hastings31826802013-10-19 00:09:25 -0700109 line_number = clinic.block_parser.line_number
110 if filename is not None:
111 add(' in file "' + filename + '"')
112 if line_number is not None:
113 add(" on line " + str(line_number))
114 add(':\n')
115 add(joined)
116 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800117 if fail:
118 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700119
120
Larry Hastingsbebf7352014-01-17 17:47:17 -0800121def warn(*args, filename=None, line_number=None):
122 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
123
124def fail(*args, filename=None, line_number=None):
125 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
126
Larry Hastings31826802013-10-19 00:09:25 -0700127
128def quoted_for_c_string(s):
129 for old, new in (
Zachary Ware9d7849f2014-01-25 03:26:20 -0600130 ('\\', '\\\\'), # must be first!
Larry Hastings31826802013-10-19 00:09:25 -0700131 ('"', '\\"'),
132 ("'", "\\'"),
133 ):
134 s = s.replace(old, new)
135 return s
136
Larry Hastings4903e002014-01-18 00:26:16 -0800137def c_repr(s):
138 return '"' + s + '"'
139
140
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700141is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
142
143def is_legal_py_identifier(s):
144 return all(is_legal_c_identifier(field) for field in s.split('.'))
145
Larry Hastingsbebf7352014-01-17 17:47:17 -0800146# identifiers that are okay in Python but aren't a good idea in C.
147# so if they're used Argument Clinic will add "_value" to the end
148# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700149c_keywords = set("""
Larry Hastings5c661892014-01-24 06:17:25 -0800150asm auto break case char const continue default do double
151else enum extern float for goto if inline int long
152register return short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800153typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700154""".strip().split())
155
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700156def ensure_legal_c_identifier(s):
157 # for now, just complain if what we're given isn't legal
158 if not is_legal_c_identifier(s):
159 fail("Illegal C identifier: {}".format(s))
160 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700161 if s in c_keywords:
162 return s + "_value"
163 return s
164
165def rstrip_lines(s):
166 text, add, output = _text_accumulator()
167 for line in s.split('\n'):
168 add(line.rstrip())
169 add('\n')
170 text.pop()
171 return output()
172
173def linear_format(s, **kwargs):
174 """
175 Perform str.format-like substitution, except:
176 * The strings substituted must be on lines by
177 themselves. (This line is the "source line".)
178 * If the substitution text is empty, the source line
179 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800180 * If the field is not recognized, the original line
181 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700182 * If the substitution text is not empty:
183 * Each line of the substituted text is indented
184 by the indent of the source line.
185 * A newline will be added to the end.
186 """
187
188 add, output = text_accumulator()
189 for line in s.split('\n'):
190 indent, curly, trailing = line.partition('{')
191 if not curly:
192 add(line)
193 add('\n')
194 continue
195
196 name, curl, trailing = trailing.partition('}')
197 if not curly or name not in kwargs:
198 add(line)
199 add('\n')
200 continue
201
202 if trailing:
203 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
204 if indent.strip():
205 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
206
207 value = kwargs[name]
208 if not value:
209 continue
210
211 value = textwrap.indent(rstrip_lines(value), indent)
212 add(value)
213 add('\n')
214
215 return output()[:-1]
216
Larry Hastingsbebf7352014-01-17 17:47:17 -0800217def indent_all_lines(s, prefix):
218 """
219 Returns 's', with 'prefix' prepended to all lines.
220
221 If the last line is empty, prefix is not prepended
222 to it. (If s is blank, returns s unchanged.)
223
224 (textwrap.indent only adds to non-blank lines.)
225 """
226 split = s.split('\n')
227 last = split.pop()
228 final = []
229 for line in split:
230 final.append(prefix)
231 final.append(line)
232 final.append('\n')
233 if last:
234 final.append(prefix)
235 final.append(last)
236 return ''.join(final)
237
238def suffix_all_lines(s, suffix):
239 """
240 Returns 's', with 'suffix' appended to all lines.
241
242 If the last line is empty, suffix is not appended
243 to it. (If s is blank, returns s unchanged.)
244 """
245 split = s.split('\n')
246 last = split.pop()
247 final = []
248 for line in split:
249 final.append(line)
250 final.append(suffix)
251 final.append('\n')
252 if last:
253 final.append(last)
254 final.append(suffix)
255 return ''.join(final)
256
257
Larry Hastingsebdcb502013-11-23 14:54:00 -0800258def version_splitter(s):
259 """Splits a version string into a tuple of integers.
260
261 The following ASCII characters are allowed, and employ
262 the following conversions:
263 a -> -3
264 b -> -2
265 c -> -1
266 (This permits Python-style version strings such as "1.4b3".)
267 """
268 version = []
269 accumulator = []
270 def flush():
271 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800272 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800273 version.append(int(''.join(accumulator)))
274 accumulator.clear()
275
276 for c in s:
277 if c.isdigit():
278 accumulator.append(c)
279 elif c == '.':
280 flush()
281 elif c in 'abc':
282 flush()
283 version.append('abc'.index(c) - 3)
284 else:
285 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
286 flush()
287 return tuple(version)
288
289def version_comparitor(version1, version2):
290 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
291 for i, (a, b) in enumerate(iterator):
292 if a < b:
293 return -1
294 if a > b:
295 return 1
296 return 0
297
Larry Hastings31826802013-10-19 00:09:25 -0700298
299class CRenderData:
300 def __init__(self):
301
302 # The C statements to declare variables.
303 # Should be full lines with \n eol characters.
304 self.declarations = []
305
306 # The C statements required to initialize the variables before the parse call.
307 # Should be full lines with \n eol characters.
308 self.initializers = []
309
Larry Hastingsc2047262014-01-25 20:43:29 -0800310 # The C statements needed to dynamically modify the values
311 # parsed by the parse call, before calling the impl.
312 self.modifications = []
313
Larry Hastings31826802013-10-19 00:09:25 -0700314 # The entries for the "keywords" array for PyArg_ParseTuple.
315 # Should be individual strings representing the names.
316 self.keywords = []
317
318 # The "format units" for PyArg_ParseTuple.
319 # Should be individual strings that will get
320 self.format_units = []
321
322 # The varargs arguments for PyArg_ParseTuple.
323 self.parse_arguments = []
324
325 # The parameter declarations for the impl function.
326 self.impl_parameters = []
327
328 # The arguments to the impl function at the time it's called.
329 self.impl_arguments = []
330
331 # For return converters: the name of the variable that
332 # should receive the value returned by the impl.
333 self.return_value = "return_value"
334
335 # For return converters: the code to convert the return
336 # value from the parse function. This is also where
337 # you should check the _return_value for errors, and
338 # "goto exit" if there are any.
339 self.return_conversion = []
340
341 # The C statements required to clean up after the impl call.
342 self.cleanup = []
343
344
Larry Hastings581ee362014-01-28 05:00:08 -0800345class FormatCounterFormatter(string.Formatter):
346 """
347 This counts how many instances of each formatter
348 "replacement string" appear in the format string.
349
350 e.g. after evaluating "string {a}, {b}, {c}, {a}"
351 the counts dict would now look like
352 {'a': 2, 'b': 1, 'c': 1}
353 """
354 def __init__(self):
355 self.counts = collections.Counter()
356
357 def get_value(self, key, args, kwargs):
358 self.counts[key] += 1
359 return ''
360
Larry Hastings31826802013-10-19 00:09:25 -0700361class Language(metaclass=abc.ABCMeta):
362
363 start_line = ""
364 body_prefix = ""
365 stop_line = ""
366 checksum_line = ""
367
Larry Hastings7726ac92014-01-31 22:03:12 -0800368 def __init__(self, filename):
369 pass
370
Larry Hastings31826802013-10-19 00:09:25 -0700371 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800372 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700373 pass
374
Larry Hastings7726ac92014-01-31 22:03:12 -0800375 def parse_line(self, line):
376 pass
377
Larry Hastings31826802013-10-19 00:09:25 -0700378 def validate(self):
Larry Hastings581ee362014-01-28 05:00:08 -0800379 def assert_only_one(attr, *additional_fields):
380 """
381 Ensures that the string found at getattr(self, attr)
382 contains exactly one formatter replacement string for
383 each valid field. The list of valid fields is
384 ['dsl_name'] extended by additional_fields.
385
386 e.g.
387 self.fmt = "{dsl_name} {a} {b}"
388
389 # this passes
390 self.assert_only_one('fmt', 'a', 'b')
391
392 # this fails, the format string has a {b} in it
393 self.assert_only_one('fmt', 'a')
394
395 # this fails, the format string doesn't have a {c} in it
396 self.assert_only_one('fmt', 'a', 'b', 'c')
397
398 # this fails, the format string has two {a}s in it,
399 # it must contain exactly one
400 self.fmt2 = '{dsl_name} {a} {a}'
401 self.assert_only_one('fmt2', 'a')
402
403 """
404 fields = ['dsl_name']
405 fields.extend(additional_fields)
406 line = getattr(self, attr)
407 fcf = FormatCounterFormatter()
408 fcf.format(line)
409 def local_fail(should_be_there_but_isnt):
410 if should_be_there_but_isnt:
411 fail("{} {} must contain {{{}}} exactly once!".format(
412 self.__class__.__name__, attr, name))
413 else:
414 fail("{} {} must not contain {{{}}}!".format(
415 self.__class__.__name__, attr, name))
416
417 for name, count in fcf.counts.items():
418 if name in fields:
419 if count > 1:
420 local_fail(True)
421 else:
422 local_fail(False)
423 for name in fields:
424 if fcf.counts.get(name) != 1:
425 local_fail(True)
426
Larry Hastings31826802013-10-19 00:09:25 -0700427 assert_only_one('start_line')
428 assert_only_one('stop_line')
Larry Hastings31826802013-10-19 00:09:25 -0700429
Larry Hastings581ee362014-01-28 05:00:08 -0800430 field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
431 assert_only_one('checksum_line', field)
Larry Hastings31826802013-10-19 00:09:25 -0700432
433
434
435class PythonLanguage(Language):
436
437 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800438 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700439 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800440 stop_line = "#[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800441 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700442
443
444def permute_left_option_groups(l):
445 """
446 Given [1, 2, 3], should yield:
447 ()
448 (3,)
449 (2, 3)
450 (1, 2, 3)
451 """
452 yield tuple()
453 accumulator = []
454 for group in reversed(l):
455 accumulator = list(group) + accumulator
456 yield tuple(accumulator)
457
458
459def permute_right_option_groups(l):
460 """
461 Given [1, 2, 3], should yield:
462 ()
463 (1,)
464 (1, 2)
465 (1, 2, 3)
466 """
467 yield tuple()
468 accumulator = []
469 for group in l:
470 accumulator.extend(group)
471 yield tuple(accumulator)
472
473
474def permute_optional_groups(left, required, right):
475 """
476 Generator function that computes the set of acceptable
477 argument lists for the provided iterables of
478 argument groups. (Actually it generates a tuple of tuples.)
479
480 Algorithm: prefer left options over right options.
481
482 If required is empty, left must also be empty.
483 """
484 required = tuple(required)
485 result = []
486
487 if not required:
488 assert not left
489
490 accumulator = []
491 counts = set()
492 for r in permute_right_option_groups(right):
493 for l in permute_left_option_groups(left):
494 t = l + required + r
495 if len(t) in counts:
496 continue
497 counts.add(len(t))
498 accumulator.append(t)
499
500 accumulator.sort(key=len)
501 return tuple(accumulator)
502
503
Larry Hastings7726ac92014-01-31 22:03:12 -0800504def strip_leading_and_trailing_blank_lines(s):
505 lines = s.rstrip().split('\n')
506 while lines:
507 line = lines[0]
508 if line.strip():
509 break
510 del lines[0]
511 return '\n'.join(lines)
512
513@functools.lru_cache()
514def normalize_snippet(s, *, indent=0):
515 """
516 Reformats s:
517 * removes leading and trailing blank lines
518 * ensures that it does not end with a newline
519 * dedents so the first nonwhite character on any line is at column "indent"
520 """
521 s = strip_leading_and_trailing_blank_lines(s)
522 s = textwrap.dedent(s)
523 if indent:
524 s = textwrap.indent(s, ' ' * indent)
525 return s
526
527
Larry Hastings31826802013-10-19 00:09:25 -0700528class CLanguage(Language):
529
Larry Hastings61272b72014-01-07 12:41:53 -0800530 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700531 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800532 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700533 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800534 stop_line = "[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800535 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700536
Larry Hastings7726ac92014-01-31 22:03:12 -0800537 def __init__(self, filename):
538 super().__init__(filename)
539 self.cpp = cpp.Monitor(filename)
540 self.cpp.fail = fail
541
542 def parse_line(self, line):
543 self.cpp.writeline(line)
544
Larry Hastingsbebf7352014-01-17 17:47:17 -0800545 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700546 function = None
547 for o in signatures:
548 if isinstance(o, Function):
549 if function:
550 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
551 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800552 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700553
554 def docstring_for_c_string(self, f):
555 text, add, output = _text_accumulator()
556 # turn docstring into a properly quoted C string
557 for line in f.docstring.split('\n'):
558 add('"')
559 add(quoted_for_c_string(line))
560 add('\\n"\n')
561
562 text.pop()
563 add('"')
564 return ''.join(text)
565
Larry Hastingsbebf7352014-01-17 17:47:17 -0800566 def output_templates(self, f):
567 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800568 assert parameters
569 assert isinstance(parameters[0].converter, self_converter)
570 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800571 converters = [p.converter for p in parameters]
572
573 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
574 default_return_converter = (not f.return_converter or
575 f.return_converter.type == 'PyObject *')
576
577 positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY)
578 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
579 first_optional = len(parameters)
580 for i, p in enumerate(parameters):
581 c = p.converter
582 if type(c) != object_converter:
583 break
584 if c.format_unit != 'O':
585 break
586 if p.default is not unspecified:
587 first_optional = min(first_optional, i)
588 else:
589 all_boring_objects = True
590
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800591 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
592
Larry Hastingsbebf7352014-01-17 17:47:17 -0800593 meth_o = (len(parameters) == 1 and
594 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
595 not converters[0].is_optional() and
596 isinstance(converters[0], object_converter) and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800597 converters[0].format_unit == 'O' and
598 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800599
Larry Hastings7726ac92014-01-31 22:03:12 -0800600 # we have to set these things before we're done:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800601 #
602 # docstring_prototype
603 # docstring_definition
604 # impl_prototype
605 # methoddef_define
606 # parser_prototype
607 # parser_definition
608 # impl_definition
Larry Hastings7726ac92014-01-31 22:03:12 -0800609 # cpp_if
610 # cpp_endif
611 # methoddef_ifndef
Larry Hastingsbebf7352014-01-17 17:47:17 -0800612
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800613 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700614
Larry Hastings7726ac92014-01-31 22:03:12 -0800615 methoddef_define = normalize_snippet("""
616 #define {methoddef_name} \\
617 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
618 """)
Larry Hastings5c661892014-01-24 06:17:25 -0800619 if new_or_init and not f.docstring:
620 docstring_prototype = docstring_definition = ''
621 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800622 docstring_prototype = normalize_snippet("""
623 PyDoc_VAR({c_basename}__doc__);
624 """)
625 docstring_definition = normalize_snippet("""
626 PyDoc_STRVAR({c_basename}__doc__,
627 {docstring});
628 """)
629 impl_definition = normalize_snippet("""
630 static {impl_return_type}
631 {c_basename}_impl({impl_parameters})
632 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800633 impl_prototype = parser_prototype = parser_definition = None
634
Larry Hastings7726ac92014-01-31 22:03:12 -0800635 parser_prototype_keyword = normalize_snippet("""
636 static PyObject *
637 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
638 """)
639
640 parser_prototype_varargs = normalize_snippet("""
641 static PyObject *
642 {c_basename}({self_type}{self_name}, PyObject *args)
643 """)
644
645 # parser_body_fields remembers the fields passed in to the
646 # previous call to parser_body. this is used for an awful hack.
Larry Hastingsc2047262014-01-25 20:43:29 -0800647 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800648 def parser_body(prototype, *fields):
649 nonlocal parser_body_fields
650 add, output = text_accumulator()
651 add(prototype)
652 parser_body_fields = fields
Larry Hastings7726ac92014-01-31 22:03:12 -0800653
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800654 fields = list(fields)
Larry Hastings7726ac92014-01-31 22:03:12 -0800655 fields.insert(0, normalize_snippet("""
656 {{
657 {return_value_declaration}
658 {declarations}
659 {initializers}
660 """) + "\n")
661 # just imagine--your code is here in the middle
662 fields.append(normalize_snippet("""
663 {modifications}
664 {return_value} = {c_basename}_impl({impl_arguments});
665 {return_conversion}
666
667 {exit_label}
668 {cleanup}
669 return return_value;
670 }}
671 """))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800672 for field in fields:
673 add('\n')
Larry Hastings7726ac92014-01-31 22:03:12 -0800674 add(field)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800675 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800676
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800677 def insert_keywords(s):
678 return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")
Larry Hastingsbebf7352014-01-17 17:47:17 -0800679
680 if not parameters:
681 # no parameters, METH_NOARGS
682
683 flags = "METH_NOARGS"
684
Larry Hastings7726ac92014-01-31 22:03:12 -0800685 parser_prototype = normalize_snippet("""
686 static PyObject *
687 {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
688 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800689 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800690
691 if default_return_converter:
Larry Hastings7726ac92014-01-31 22:03:12 -0800692 parser_definition = parser_prototype + '\n' + normalize_snippet("""
693 {{
694 return {c_basename}_impl({impl_arguments});
695 }}
696 """)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800697 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800698 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700699
Larry Hastingsbebf7352014-01-17 17:47:17 -0800700 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800701 flags = "METH_O"
Larry Hastings7726ac92014-01-31 22:03:12 -0800702
703 meth_o_prototype = normalize_snippet("""
704 static PyObject *
705 {c_basename}({impl_parameters})
706 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800707
Larry Hastingsbebf7352014-01-17 17:47:17 -0800708 if default_return_converter:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800709 # maps perfectly to METH_O, doesn't need a return converter.
710 # so we skip making a parse function
711 # and call directly into the impl function.
Larry Hastingsbebf7352014-01-17 17:47:17 -0800712 impl_prototype = parser_prototype = parser_definition = ''
Larry Hastings7726ac92014-01-31 22:03:12 -0800713 impl_definition = meth_o_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800714 else:
Larry Hastings7726ac92014-01-31 22:03:12 -0800715 # SLIGHT HACK
716 # use impl_parameters for the parser here!
717 parser_prototype = meth_o_prototype
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800718 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700719
Larry Hastingsbebf7352014-01-17 17:47:17 -0800720 elif has_option_groups:
721 # positional parameters with option groups
722 # (we have to generate lots of PyArg_ParseTuple calls
723 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700724
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800725 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800726 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700727
Larry Hastings7726ac92014-01-31 22:03:12 -0800728 parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
Larry Hastings31826802013-10-19 00:09:25 -0700729
Larry Hastingsbebf7352014-01-17 17:47:17 -0800730 elif positional and all_boring_objects:
731 # positional-only, but no option groups,
732 # and nothing but normal objects:
733 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700734
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800735 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800736 parser_prototype = parser_prototype_varargs
Larry Hastings31826802013-10-19 00:09:25 -0700737
Larry Hastings7726ac92014-01-31 22:03:12 -0800738 parser_definition = parser_body(parser_prototype, normalize_snippet("""
739 if (!PyArg_UnpackTuple(args, "{name}",
740 {unpack_min}, {unpack_max},
741 {parse_arguments}))
742 goto exit;
743 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800744
745 elif positional:
746 # positional-only, but no option groups
747 # we only need one call to PyArg_ParseTuple
748
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800749 flags = "METH_VARARGS"
Larry Hastings7726ac92014-01-31 22:03:12 -0800750 parser_prototype = parser_prototype_varargs
Larry Hastingsbebf7352014-01-17 17:47:17 -0800751
Larry Hastings7726ac92014-01-31 22:03:12 -0800752 parser_definition = parser_body(parser_prototype, normalize_snippet("""
753 if (!PyArg_ParseTuple(args,
754 "{format_units}:{name}",
755 {parse_arguments}))
756 goto exit;
757 """, indent=4))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800758
759 else:
760 # positional-or-keyword arguments
761 flags = "METH_VARARGS|METH_KEYWORDS"
762
Larry Hastings7726ac92014-01-31 22:03:12 -0800763 parser_prototype = parser_prototype_keyword
Larry Hastingsbebf7352014-01-17 17:47:17 -0800764
Larry Hastings7726ac92014-01-31 22:03:12 -0800765 body = normalize_snippet("""
766 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
767 "{format_units}:{name}", _keywords,
768 {parse_arguments}))
769 goto exit;
770 """, indent=4)
771 parser_definition = parser_body(parser_prototype, normalize_snippet("""
772 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
773 "{format_units}:{name}", _keywords,
774 {parse_arguments}))
775 goto exit;
776 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800777 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700778
Larry Hastings31826802013-10-19 00:09:25 -0700779
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800780 if new_or_init:
781 methoddef_define = ''
782
783 if f.kind == METHOD_NEW:
Larry Hastings7726ac92014-01-31 22:03:12 -0800784 parser_prototype = parser_prototype_keyword
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800785 else:
786 return_value_declaration = "int return_value = -1;"
Larry Hastings7726ac92014-01-31 22:03:12 -0800787 parser_prototype = normalize_snippet("""
788 static int
789 {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
790 """)
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800791
792 fields = list(parser_body_fields)
793 parses_positional = 'METH_NOARGS' not in flags
794 parses_keywords = 'METH_KEYWORDS' in flags
795 if parses_keywords:
796 assert parses_positional
797
798 if not parses_keywords:
Larry Hastings7726ac92014-01-31 22:03:12 -0800799 fields.insert(0, normalize_snippet("""
800 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs))
801 goto exit;
802 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800803 if not parses_positional:
Larry Hastings7726ac92014-01-31 22:03:12 -0800804 fields.insert(0, normalize_snippet("""
805 if ({self_type_check}!_PyArg_NoPositional("{name}", args))
806 goto exit;
807 """, indent=4))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800808
809 parser_definition = parser_body(parser_prototype, *fields)
810 if parses_keywords:
811 parser_definition = insert_keywords(parser_definition)
812
Larry Hastings31826802013-10-19 00:09:25 -0700813
Larry Hastingsbebf7352014-01-17 17:47:17 -0800814 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800815 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700816
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800817 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700818
Larry Hastings7726ac92014-01-31 22:03:12 -0800819 methoddef_ifndef = ''
820 conditional = self.cpp.condition()
821 if not conditional:
822 cpp_if = cpp_endif = ''
823 else:
824 cpp_if = "#if " + conditional
825 cpp_endif = "#endif /* " + conditional + " */"
826
Larry Hastings0759f842015-04-03 13:09:02 -0700827 if methoddef_define and f.name not in clinic.ifndef_symbols:
828 clinic.ifndef_symbols.add(f.name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800829 methoddef_ifndef = normalize_snippet("""
830 #ifndef {methoddef_name}
831 #define {methoddef_name}
832 #endif /* !defined({methoddef_name}) */
833 """)
834
835
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800836 # add ';' to the end of parser_prototype and impl_prototype
837 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800838 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800839 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800840 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800841 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700842
Larry Hastingsbebf7352014-01-17 17:47:17 -0800843 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800844 impl_prototype = impl_definition
845 if impl_prototype:
846 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700847
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800848 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800849
850 d = {
851 "docstring_prototype" : docstring_prototype,
852 "docstring_definition" : docstring_definition,
853 "impl_prototype" : impl_prototype,
854 "methoddef_define" : methoddef_define,
855 "parser_prototype" : parser_prototype,
856 "parser_definition" : parser_definition,
857 "impl_definition" : impl_definition,
Larry Hastings7726ac92014-01-31 22:03:12 -0800858 "cpp_if" : cpp_if,
859 "cpp_endif" : cpp_endif,
860 "methoddef_ifndef" : methoddef_ifndef,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800861 }
862
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800863 # make sure we didn't forget to assign something,
864 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -0800865 d2 = {}
866 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800867 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800868 if value:
869 value = '\n' + value + '\n'
870 d2[name] = value
871 return d2
Larry Hastings31826802013-10-19 00:09:25 -0700872
873 @staticmethod
874 def group_to_variable_name(group):
875 adjective = "left_" if group < 0 else "right_"
876 return "group_" + adjective + str(abs(group))
877
878 def render_option_group_parsing(self, f, template_dict):
879 # positional only, grouped, optional arguments!
880 # can be optional on the left or right.
881 # here's an example:
882 #
883 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
884 #
885 # Here group D are required, and all other groups are optional.
886 # (Group D's "group" is actually None.)
887 # We can figure out which sets of arguments we have based on
888 # how many arguments are in the tuple.
889 #
890 # Note that you need to count up on both sides. For example,
891 # you could have groups C+D, or C+D+E, or C+D+E+F.
892 #
893 # What if the number of arguments leads us to an ambiguous result?
894 # Clinic prefers groups on the left. So in the above example,
895 # five arguments would map to B+C, not C+D.
896
897 add, output = text_accumulator()
898 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800899 if isinstance(parameters[0].converter, self_converter):
900 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -0700901
902 groups = []
903 group = None
904 left = []
905 right = []
906 required = []
907 last = unspecified
908
909 for p in parameters:
910 group_id = p.group
911 if group_id != last:
912 last = group_id
913 group = []
914 if group_id < 0:
915 left.append(group)
916 elif group_id == 0:
917 group = required
918 else:
919 right.append(group)
920 group.append(p)
921
922 count_min = sys.maxsize
923 count_max = -1
924
Larry Hastings2a727912014-01-16 11:32:01 -0800925 add("switch (PyTuple_GET_SIZE(args)) {{\n")
Larry Hastings31826802013-10-19 00:09:25 -0700926 for subset in permute_optional_groups(left, required, right):
927 count = len(subset)
928 count_min = min(count_min, count)
929 count_max = max(count_max, count)
930
Larry Hastings583baa82014-01-12 08:49:30 -0800931 if count == 0:
932 add(""" case 0:
933 break;
934""")
935 continue
936
Larry Hastings31826802013-10-19 00:09:25 -0700937 group_ids = {p.group for p in subset} # eliminate duplicates
938 d = {}
939 d['count'] = count
940 d['name'] = f.name
941 d['groups'] = sorted(group_ids)
942 d['format_units'] = "".join(p.converter.format_unit for p in subset)
943
944 parse_arguments = []
945 for p in subset:
946 p.converter.parse_argument(parse_arguments)
947 d['parse_arguments'] = ", ".join(parse_arguments)
948
949 group_ids.discard(0)
950 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
951 lines = "\n".join(lines)
952
953 s = """
954 case {count}:
955 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
Larry Hastings46258262014-01-22 03:05:49 -0800956 goto exit;
Larry Hastings31826802013-10-19 00:09:25 -0700957 {group_booleans}
958 break;
959"""[1:]
960 s = linear_format(s, group_booleans=lines)
961 s = s.format_map(d)
962 add(s)
963
964 add(" default:\n")
965 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
966 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -0800967 add(' goto exit;\n')
Larry Hastings31826802013-10-19 00:09:25 -0700968 add("}}")
969 template_dict['option_group_parsing'] = output()
970
Larry Hastingsbebf7352014-01-17 17:47:17 -0800971 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -0700972 if not f:
973 return ""
974
975 add, output = text_accumulator()
976 data = CRenderData()
977
Larry Hastings7726ac92014-01-31 22:03:12 -0800978 assert f.parameters, "We should always have a 'self' at this point!"
979 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -0700980 converters = [p.converter for p in parameters]
981
Larry Hastings5c661892014-01-24 06:17:25 -0800982 templates = self.output_templates(f)
983
984 f_self = parameters[0]
985 selfless = parameters[1:]
986 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
987
988 last_group = 0
989 first_optional = len(selfless)
990 positional = selfless and selfless[-1].kind == inspect.Parameter.POSITIONAL_ONLY
991 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
992 default_return_converter = (not f.return_converter or
993 f.return_converter.type == 'PyObject *')
994 has_option_groups = False
995
996 # offset i by -1 because first_optional needs to ignore self
997 for i, p in enumerate(parameters, -1):
998 c = p.converter
999
1000 if (i != -1) and (p.default is not unspecified):
1001 first_optional = min(first_optional, i)
1002
1003 # insert group variable
1004 group = p.group
1005 if last_group != group:
1006 last_group = group
1007 if group:
1008 group_name = self.group_to_variable_name(group)
1009 data.impl_arguments.append(group_name)
1010 data.declarations.append("int " + group_name + " = 0;")
1011 data.impl_parameters.append("int " + group_name)
1012 has_option_groups = True
1013
1014 c.render(p, data)
1015
1016 if has_option_groups and (not positional):
1017 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1018
1019 # HACK
1020 # when we're METH_O, but have a custom return converter,
1021 # we use "impl_parameters" for the parsing function
1022 # because that works better. but that means we must
Berker Peksagf23530f2014-10-19 18:04:38 +03001023 # suppress actually declaring the impl's parameters
Larry Hastings5c661892014-01-24 06:17:25 -08001024 # as variables in the parsing function. but since it's
1025 # METH_O, we have exactly one anyway, so we know exactly
1026 # where it is.
1027 if ("METH_O" in templates['methoddef_define'] and
1028 not default_return_converter):
1029 data.declarations.pop(0)
1030
Larry Hastings31826802013-10-19 00:09:25 -07001031 template_dict = {}
1032
1033 full_name = f.full_name
1034 template_dict['full_name'] = full_name
1035
Larry Hastings5c661892014-01-24 06:17:25 -08001036 if new_or_init:
1037 name = f.cls.name
1038 else:
1039 name = f.name
1040
Larry Hastings31826802013-10-19 00:09:25 -07001041 template_dict['name'] = name
1042
Larry Hastings8666e652014-01-12 14:12:59 -08001043 if f.c_basename:
1044 c_basename = f.c_basename
1045 else:
1046 fields = full_name.split(".")
1047 if fields[-1] == '__new__':
1048 fields.pop()
1049 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001050
Larry Hastings31826802013-10-19 00:09:25 -07001051 template_dict['c_basename'] = c_basename
1052
1053 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1054 template_dict['methoddef_name'] = methoddef_name
1055
1056 template_dict['docstring'] = self.docstring_for_c_string(f)
1057
Larry Hastingsc2047262014-01-25 20:43:29 -08001058 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001059 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001060
Larry Hastings31826802013-10-19 00:09:25 -07001061 f.return_converter.render(f, data)
1062 template_dict['impl_return_type'] = f.return_converter.type
1063
1064 template_dict['declarations'] = "\n".join(data.declarations)
1065 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001066 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001067 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1068 template_dict['format_units'] = ''.join(data.format_units)
1069 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1070 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1071 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
1072 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
1073 template_dict['cleanup'] = "".join(data.cleanup)
1074 template_dict['return_value'] = data.return_value
1075
Larry Hastings5c661892014-01-24 06:17:25 -08001076 # used by unpack tuple code generator
1077 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1078 unpack_min = first_optional
1079 unpack_max = len(selfless)
1080 template_dict['unpack_min'] = str(unpack_min)
1081 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001082
Larry Hastingsbebf7352014-01-17 17:47:17 -08001083 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001084 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001085
Larry Hastings0759f842015-04-03 13:09:02 -07001086 # buffers, not destination
1087 for name, destination in clinic.destination_buffers.items():
Larry Hastingsbebf7352014-01-17 17:47:17 -08001088 template = templates[name]
1089 if has_option_groups:
1090 template = linear_format(template,
1091 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001092 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001093 declarations=template_dict['declarations'],
1094 return_conversion=template_dict['return_conversion'],
1095 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001096 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001097 cleanup=template_dict['cleanup'],
1098 )
Larry Hastings31826802013-10-19 00:09:25 -07001099
Larry Hastingsbebf7352014-01-17 17:47:17 -08001100 # Only generate the "exit:" label
1101 # if we have any gotos
1102 need_exit_label = "goto exit;" in template
1103 template = linear_format(template,
1104 exit_label="exit:" if need_exit_label else ''
1105 )
Larry Hastings31826802013-10-19 00:09:25 -07001106
Larry Hastingsbebf7352014-01-17 17:47:17 -08001107 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001108
Larry Hastingsbebf7352014-01-17 17:47:17 -08001109 if clinic.line_prefix:
1110 s = indent_all_lines(s, clinic.line_prefix)
1111 if clinic.line_suffix:
1112 s = suffix_all_lines(s, clinic.line_suffix)
1113
1114 destination.append(s)
1115
1116 return clinic.get_destination('block').dump()
1117
Larry Hastings31826802013-10-19 00:09:25 -07001118
1119
Larry Hastings5c661892014-01-24 06:17:25 -08001120
Larry Hastings31826802013-10-19 00:09:25 -07001121@contextlib.contextmanager
1122def OverrideStdioWith(stdout):
1123 saved_stdout = sys.stdout
1124 sys.stdout = stdout
1125 try:
1126 yield
1127 finally:
1128 assert sys.stdout is stdout
1129 sys.stdout = saved_stdout
1130
1131
Larry Hastings2623c8c2014-02-08 22:15:29 -08001132def create_regex(before, after, word=True, whole_line=True):
Larry Hastings31826802013-10-19 00:09:25 -07001133 """Create an re object for matching marker lines."""
Larry Hastings581ee362014-01-28 05:00:08 -08001134 group_re = "\w+" if word else ".+"
Larry Hastings2623c8c2014-02-08 22:15:29 -08001135 pattern = r'{}({}){}'
1136 if whole_line:
1137 pattern = '^' + pattern + '$'
Larry Hastings581ee362014-01-28 05:00:08 -08001138 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1139 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001140
1141
1142class Block:
1143 r"""
1144 Represents a single block of text embedded in
1145 another file. If dsl_name is None, the block represents
1146 verbatim text, raw original text from the file, in
1147 which case "input" will be the only non-false member.
1148 If dsl_name is not None, the block represents a Clinic
1149 block.
1150
1151 input is always str, with embedded \n characters.
1152 input represents the original text from the file;
1153 if it's a Clinic block, it is the original text with
1154 the body_prefix and redundant leading whitespace removed.
1155
1156 dsl_name is either str or None. If str, it's the text
1157 found on the start line of the block between the square
1158 brackets.
1159
1160 signatures is either list or None. If it's a list,
1161 it may only contain clinic.Module, clinic.Class, and
1162 clinic.Function objects. At the moment it should
1163 contain at most one of each.
1164
1165 output is either str or None. If str, it's the output
1166 from this block, with embedded '\n' characters.
1167
1168 indent is either str or None. It's the leading whitespace
1169 that was found on every line of input. (If body_prefix is
1170 not empty, this is the indent *after* removing the
1171 body_prefix.)
1172
1173 preindent is either str or None. It's the whitespace that
1174 was found in front of every line of input *before* the
1175 "body_prefix" (see the Language object). If body_prefix
1176 is empty, preindent must always be empty too.
1177
1178 To illustrate indent and preindent: Assume that '_'
1179 represents whitespace. If the block processed was in a
1180 Python file, and looked like this:
1181 ____#/*[python]
1182 ____#__for a in range(20):
1183 ____#____print(a)
1184 ____#[python]*/
1185 "preindent" would be "____" and "indent" would be "__".
1186
1187 """
1188 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1189 assert isinstance(input, str)
1190 self.input = input
1191 self.dsl_name = dsl_name
1192 self.signatures = signatures or []
1193 self.output = output
1194 self.indent = indent
1195 self.preindent = preindent
1196
Larry Hastings581ee362014-01-28 05:00:08 -08001197 def __repr__(self):
1198 dsl_name = self.dsl_name or "text"
1199 def summarize(s):
1200 s = repr(s)
1201 if len(s) > 30:
1202 return s[:26] + "..." + s[0]
1203 return s
1204 return "".join((
1205 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1206
Larry Hastings31826802013-10-19 00:09:25 -07001207
1208class BlockParser:
1209 """
1210 Block-oriented parser for Argument Clinic.
1211 Iterator, yields Block objects.
1212 """
1213
1214 def __init__(self, input, language, *, verify=True):
1215 """
1216 "input" should be a str object
1217 with embedded \n characters.
1218
1219 "language" should be a Language object.
1220 """
1221 language.validate()
1222
1223 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1224 self.block_start_line_number = self.line_number = 0
1225
1226 self.language = language
1227 before, _, after = language.start_line.partition('{dsl_name}')
1228 assert _ == '{dsl_name}'
Larry Hastings2623c8c2014-02-08 22:15:29 -08001229 self.find_start_re = create_regex(before, after, whole_line=False)
Larry Hastings31826802013-10-19 00:09:25 -07001230 self.start_re = create_regex(before, after)
1231 self.verify = verify
1232 self.last_checksum_re = None
1233 self.last_dsl_name = None
1234 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001235 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001236
1237 def __iter__(self):
1238 return self
1239
1240 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001241 while True:
1242 if not self.input:
1243 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001244
Larry Hastingsbebf7352014-01-17 17:47:17 -08001245 if self.dsl_name:
1246 return_value = self.parse_clinic_block(self.dsl_name)
1247 self.dsl_name = None
1248 self.first_block = False
1249 return return_value
1250 block = self.parse_verbatim_block()
1251 if self.first_block and not block.input:
1252 continue
1253 self.first_block = False
1254 return block
1255
Larry Hastings31826802013-10-19 00:09:25 -07001256
1257 def is_start_line(self, line):
1258 match = self.start_re.match(line.lstrip())
1259 return match.group(1) if match else None
1260
Larry Hastingse1b82532014-07-27 16:22:20 +02001261 def _line(self, lookahead=False):
Larry Hastings31826802013-10-19 00:09:25 -07001262 self.line_number += 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001263 line = self.input.pop()
Larry Hastingse1b82532014-07-27 16:22:20 +02001264 if not lookahead:
1265 self.language.parse_line(line)
Larry Hastings7726ac92014-01-31 22:03:12 -08001266 return line
Larry Hastings31826802013-10-19 00:09:25 -07001267
1268 def parse_verbatim_block(self):
1269 add, output = text_accumulator()
1270 self.block_start_line_number = self.line_number
1271
1272 while self.input:
1273 line = self._line()
1274 dsl_name = self.is_start_line(line)
1275 if dsl_name:
1276 self.dsl_name = dsl_name
1277 break
1278 add(line)
1279
1280 return Block(output())
1281
1282 def parse_clinic_block(self, dsl_name):
1283 input_add, input_output = text_accumulator()
1284 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001285 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001286 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1287
Larry Hastings90261132014-01-07 12:21:08 -08001288 def is_stop_line(line):
1289 # make sure to recognize stop line even if it
1290 # doesn't end with EOL (it could be the very end of the file)
1291 if not line.startswith(stop_line):
1292 return False
1293 remainder = line[len(stop_line):]
1294 return (not remainder) or remainder.isspace()
1295
Larry Hastings31826802013-10-19 00:09:25 -07001296 # consume body of program
1297 while self.input:
1298 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001299 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001300 break
1301 if body_prefix:
1302 line = line.lstrip()
1303 assert line.startswith(body_prefix)
1304 line = line[len(body_prefix):]
1305 input_add(line)
1306
1307 # consume output and checksum line, if present.
1308 if self.last_dsl_name == dsl_name:
1309 checksum_re = self.last_checksum_re
1310 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001311 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1312 assert _ == '{arguments}'
1313 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001314 self.last_dsl_name = dsl_name
1315 self.last_checksum_re = checksum_re
1316
1317 # scan forward for checksum line
1318 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001319 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001320 while self.input:
Larry Hastingse1b82532014-07-27 16:22:20 +02001321 line = self._line(lookahead=True)
Larry Hastings31826802013-10-19 00:09:25 -07001322 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001323 arguments = match.group(1) if match else None
1324 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001325 break
1326 output_add(line)
1327 if self.is_start_line(line):
1328 break
1329
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001330 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001331 if arguments:
1332 d = {}
1333 for field in shlex.split(arguments):
1334 name, equals, value = field.partition('=')
1335 if not equals:
1336 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1337 d[name.strip()] = value.strip()
1338
Larry Hastings31826802013-10-19 00:09:25 -07001339 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001340 if 'input' in d:
1341 checksum = d['output']
1342 input_checksum = d['input']
1343 else:
1344 checksum = d['checksum']
1345 input_checksum = None
1346
1347 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001348 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001349 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1350 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001351 "the end marker,\n"
1352 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001353 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001354 else:
1355 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001356 output_lines = output.splitlines(keepends=True)
1357 self.line_number -= len(output_lines)
1358 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001359 output = None
1360
1361 return Block(input_output(), dsl_name, output=output)
1362
1363
1364class BlockPrinter:
1365
1366 def __init__(self, language, f=None):
1367 self.language = language
1368 self.f = f or io.StringIO()
1369
1370 def print_block(self, block):
1371 input = block.input
1372 output = block.output
1373 dsl_name = block.dsl_name
1374 write = self.f.write
1375
Larry Hastings31826802013-10-19 00:09:25 -07001376 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1377
1378 if not dsl_name:
1379 write(input)
1380 return
1381
1382 write(self.language.start_line.format(dsl_name=dsl_name))
1383 write("\n")
1384
1385 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1386 if not body_prefix:
1387 write(input)
1388 else:
1389 for line in input.split('\n'):
1390 write(body_prefix)
1391 write(line)
1392 write("\n")
1393
1394 write(self.language.stop_line.format(dsl_name=dsl_name))
1395 write("\n")
1396
Larry Hastings581ee362014-01-28 05:00:08 -08001397 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001398 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001399 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001400 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001401 output += '\n'
1402 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001403
Larry Hastings581ee362014-01-28 05:00:08 -08001404 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1405 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001406 write("\n")
1407
Larry Hastingsbebf7352014-01-17 17:47:17 -08001408 def write(self, text):
1409 self.f.write(text)
1410
1411
Larry Hastings0759f842015-04-03 13:09:02 -07001412class BufferSeries:
1413 """
1414 Behaves like a "defaultlist".
1415 When you ask for an index that doesn't exist yet,
1416 the object grows the list until that item exists.
1417 So o[n] will always work.
1418
1419 Supports negative indices for actual items.
1420 e.g. o[-1] is an element immediately preceding o[0].
1421 """
1422
1423 def __init__(self):
1424 self._start = 0
1425 self._array = []
1426 self._constructor = _text_accumulator
1427
1428 def __getitem__(self, i):
1429 i -= self._start
1430 if i < 0:
1431 self._start += i
1432 prefix = [self._constructor() for x in range(-i)]
1433 self._array = prefix + self._array
1434 i = 0
1435 while i >= len(self._array):
1436 self._array.append(self._constructor())
1437 return self._array[i]
1438
1439 def clear(self):
1440 for ta in self._array:
1441 ta._text.clear()
1442
1443 def dump(self):
1444 texts = [ta.output() for ta in self._array]
1445 return "".join(texts)
1446
1447
Larry Hastingsbebf7352014-01-17 17:47:17 -08001448class Destination:
1449 def __init__(self, name, type, clinic, *args):
1450 self.name = name
1451 self.type = type
1452 self.clinic = clinic
Larry Hastings0759f842015-04-03 13:09:02 -07001453 valid_types = ('buffer', 'file', 'suppress')
Larry Hastingsbebf7352014-01-17 17:47:17 -08001454 if type not in valid_types:
1455 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1456 extra_arguments = 1 if type == "file" else 0
1457 if len(args) < extra_arguments:
1458 fail("Not enough arguments for destination " + name + " new " + type)
1459 if len(args) > extra_arguments:
1460 fail("Too many arguments for destination " + name + " new " + type)
1461 if type =='file':
1462 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001463 filename = clinic.filename
1464 d['path'] = filename
1465 dirname, basename = os.path.split(filename)
1466 if not dirname:
1467 dirname = '.'
1468 d['dirname'] = dirname
1469 d['basename'] = basename
1470 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001471 self.filename = args[0].format_map(d)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001472
Larry Hastings0759f842015-04-03 13:09:02 -07001473 self.buffers = BufferSeries()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001474
1475 def __repr__(self):
1476 if self.type == 'file':
1477 file_repr = " " + repr(self.filename)
1478 else:
1479 file_repr = ''
1480 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1481
1482 def clear(self):
1483 if self.type != 'buffer':
1484 fail("Can't clear destination" + self.name + " , it's not of type buffer")
Larry Hastings0759f842015-04-03 13:09:02 -07001485 self.buffers.clear()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001486
1487 def dump(self):
Larry Hastings0759f842015-04-03 13:09:02 -07001488 return self.buffers.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001489
Larry Hastings31826802013-10-19 00:09:25 -07001490
1491# maps strings to Language objects.
1492# "languages" maps the name of the language ("C", "Python").
1493# "extensions" maps the file extension ("c", "py").
1494languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001495extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1496extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001497
1498
1499# maps strings to callables.
1500# these callables must be of the form:
1501# def foo(name, default, *, ...)
1502# The callable may have any number of keyword-only parameters.
1503# The callable must return a CConverter object.
1504# The callable should not call builtins.print.
1505converters = {}
1506
1507# maps strings to callables.
1508# these callables follow the same rules as those for "converters" above.
1509# note however that they will never be called with keyword-only parameters.
1510legacy_converters = {}
1511
1512
1513# maps strings to callables.
1514# these callables must be of the form:
1515# def foo(*, ...)
1516# The callable may have any number of keyword-only parameters.
1517# The callable must return a CConverter object.
1518# The callable should not call builtins.print.
1519return_converters = {}
1520
Larry Hastings7726ac92014-01-31 22:03:12 -08001521clinic = None
Larry Hastings31826802013-10-19 00:09:25 -07001522class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001523
1524 presets_text = """
Larry Hastings7726ac92014-01-31 22:03:12 -08001525preset block
1526everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001527methoddef_ifndef buffer 1
Larry Hastings7726ac92014-01-31 22:03:12 -08001528docstring_prototype suppress
1529parser_prototype suppress
1530cpp_if suppress
1531cpp_endif suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001532
Larry Hastingsbebf7352014-01-17 17:47:17 -08001533preset original
1534everything block
Larry Hastings0759f842015-04-03 13:09:02 -07001535methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001536docstring_prototype suppress
1537parser_prototype suppress
Larry Hastings7726ac92014-01-31 22:03:12 -08001538cpp_if suppress
1539cpp_endif suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001540
1541preset file
1542everything file
Larry Hastings0759f842015-04-03 13:09:02 -07001543methoddef_ifndef file 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001544docstring_prototype suppress
1545parser_prototype suppress
1546impl_definition block
1547
1548preset buffer
1549everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001550methoddef_ifndef buffer 1
1551impl_definition block
Larry Hastingsbebf7352014-01-17 17:47:17 -08001552docstring_prototype suppress
1553impl_prototype suppress
1554parser_prototype suppress
Larry Hastingsbebf7352014-01-17 17:47:17 -08001555
1556preset partial-buffer
1557everything buffer
Larry Hastings0759f842015-04-03 13:09:02 -07001558methoddef_ifndef buffer 1
Larry Hastingsbebf7352014-01-17 17:47:17 -08001559docstring_prototype block
1560impl_prototype suppress
1561methoddef_define block
1562parser_prototype block
1563impl_definition block
1564
Larry Hastingsbebf7352014-01-17 17:47:17 -08001565"""
1566
Larry Hastings581ee362014-01-28 05:00:08 -08001567 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001568 # maps strings to Parser objects.
1569 # (instantiated from the "parsers" global.)
1570 self.parsers = {}
1571 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001572 if printer:
1573 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001574 self.printer = printer or BlockPrinter(language)
1575 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001576 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001577 self.filename = filename
1578 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001579 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001580 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001581
Larry Hastingsbebf7352014-01-17 17:47:17 -08001582 self.line_prefix = self.line_suffix = ''
1583
1584 self.destinations = {}
1585 self.add_destination("block", "buffer")
1586 self.add_destination("suppress", "suppress")
1587 self.add_destination("buffer", "buffer")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001588 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001589 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001590
Larry Hastings0759f842015-04-03 13:09:02 -07001591 d = self.get_destination_buffer
1592 self.destination_buffers = collections.OrderedDict((
Larry Hastings7726ac92014-01-31 22:03:12 -08001593 ('cpp_if', d('suppress')),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001594 ('docstring_prototype', d('suppress')),
1595 ('docstring_definition', d('block')),
1596 ('methoddef_define', d('block')),
1597 ('impl_prototype', d('block')),
1598 ('parser_prototype', d('suppress')),
1599 ('parser_definition', d('block')),
Larry Hastings7726ac92014-01-31 22:03:12 -08001600 ('cpp_endif', d('suppress')),
Larry Hastings0759f842015-04-03 13:09:02 -07001601 ('methoddef_ifndef', d('buffer', 1)),
Larry Hastingsbebf7352014-01-17 17:47:17 -08001602 ('impl_definition', d('block')),
1603 ))
1604
Larry Hastings0759f842015-04-03 13:09:02 -07001605 self.destination_buffers_stack = []
1606 self.ifndef_symbols = set()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001607
1608 self.presets = {}
1609 preset = None
1610 for line in self.presets_text.strip().split('\n'):
1611 line = line.strip()
1612 if not line:
1613 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001614 name, value, *options = line.split()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001615 if name == 'preset':
1616 self.presets[value] = preset = collections.OrderedDict()
1617 continue
1618
Larry Hastings0759f842015-04-03 13:09:02 -07001619 if len(options):
1620 index = int(options[0])
1621 else:
1622 index = 0
1623 buffer = self.get_destination_buffer(value, index)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001624
1625 if name == 'everything':
Larry Hastings0759f842015-04-03 13:09:02 -07001626 for name in self.destination_buffers:
1627 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001628 continue
1629
Larry Hastings0759f842015-04-03 13:09:02 -07001630 assert name in self.destination_buffers
1631 preset[name] = buffer
Larry Hastingsbebf7352014-01-17 17:47:17 -08001632
Larry Hastings31826802013-10-19 00:09:25 -07001633 global clinic
1634 clinic = self
1635
Larry Hastingsbebf7352014-01-17 17:47:17 -08001636 def add_destination(self, name, type, *args):
1637 if name in self.destinations:
1638 fail("Destination already exists: " + repr(name))
1639 self.destinations[name] = Destination(name, type, self, *args)
1640
Larry Hastings0759f842015-04-03 13:09:02 -07001641 def get_destination(self, name):
1642 d = self.destinations.get(name)
1643 if not d:
1644 fail("Destination does not exist: " + repr(name))
1645 return d
1646
1647 def get_destination_buffer(self, name, item=0):
1648 d = self.get_destination(name)
1649 return d.buffers[item]
1650
Larry Hastings31826802013-10-19 00:09:25 -07001651 def parse(self, input):
1652 printer = self.printer
1653 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1654 for block in self.block_parser:
1655 dsl_name = block.dsl_name
1656 if dsl_name:
1657 if dsl_name not in self.parsers:
1658 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1659 self.parsers[dsl_name] = parsers[dsl_name](self)
1660 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001661 try:
1662 parser.parse(block)
1663 except Exception:
1664 fail('Exception raised during parsing:\n' +
1665 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001666 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001667
1668 second_pass_replacements = {}
1669
Larry Hastings0759f842015-04-03 13:09:02 -07001670 # these are destinations not buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08001671 for name, destination in self.destinations.items():
1672 if destination.type == 'suppress':
1673 continue
Larry Hastings0759f842015-04-03 13:09:02 -07001674 output = destination.dump()
Larry Hastingsbebf7352014-01-17 17:47:17 -08001675
1676 if output:
1677
1678 block = Block("", dsl_name="clinic", output=output)
1679
1680 if destination.type == 'buffer':
1681 block.input = "dump " + name + "\n"
1682 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1683 printer.write("\n")
1684 printer.print_block(block)
1685 continue
1686
1687 if destination.type == 'file':
1688 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001689 dirname = os.path.dirname(destination.filename)
1690 try:
1691 os.makedirs(dirname)
1692 except FileExistsError:
1693 if not os.path.isdir(dirname):
1694 fail("Can't write to destination {}, "
1695 "can't make directory {}!".format(
1696 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001697 if self.verify:
1698 with open(destination.filename, "rt") as f:
1699 parser_2 = BlockParser(f.read(), language=self.language)
1700 blocks = list(parser_2)
1701 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1702 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001703 except FileNotFoundError:
1704 pass
1705
1706 block.input = 'preserve\n'
1707 printer_2 = BlockPrinter(self.language)
1708 printer_2.print_block(block)
1709 with open(destination.filename, "wt") as f:
1710 f.write(printer_2.f.getvalue())
1711 continue
1712 text = printer.f.getvalue()
1713
1714 if second_pass_replacements:
1715 printer_2 = BlockPrinter(self.language)
1716 parser_2 = BlockParser(text, self.language)
1717 changed = False
1718 for block in parser_2:
1719 if block.dsl_name:
1720 for id, replacement in second_pass_replacements.items():
1721 if id in block.output:
1722 changed = True
1723 block.output = block.output.replace(id, replacement)
1724 printer_2.print_block(block)
1725 if changed:
1726 text = printer_2.f.getvalue()
1727
1728 return text
1729
Larry Hastings31826802013-10-19 00:09:25 -07001730
1731 def _module_and_class(self, fields):
1732 """
1733 fields should be an iterable of field names.
1734 returns a tuple of (module, class).
1735 the module object could actually be self (a clinic object).
1736 this function is only ever used to find the parent of where
1737 a new class/module should go.
1738 """
1739 in_classes = False
1740 parent = module = self
1741 cls = None
1742 so_far = []
1743
1744 for field in fields:
1745 so_far.append(field)
1746 if not in_classes:
1747 child = parent.modules.get(field)
1748 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001749 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001750 continue
1751 in_classes = True
1752 if not hasattr(parent, 'classes'):
1753 return module, cls
1754 child = parent.classes.get(field)
1755 if not child:
1756 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1757 cls = parent = child
1758
1759 return module, cls
1760
1761
Larry Hastings581ee362014-01-28 05:00:08 -08001762def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001763 extension = os.path.splitext(filename)[1][1:]
1764 if not extension:
1765 fail("Can't extract file type for file " + repr(filename))
1766
1767 try:
Larry Hastings7726ac92014-01-31 22:03:12 -08001768 language = extensions[extension](filename)
Larry Hastings31826802013-10-19 00:09:25 -07001769 except KeyError:
1770 fail("Can't identify file type for file " + repr(filename))
1771
Larry Hastings31826802013-10-19 00:09:25 -07001772 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001773 raw = f.read()
1774
Larry Hastings2623c8c2014-02-08 22:15:29 -08001775 # exit quickly if there are no clinic markers in the file
1776 find_start_re = BlockParser("", language).find_start_re
1777 if not find_start_re.search(raw):
1778 return
1779
1780 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001781 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001782 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001783 return
Larry Hastings31826802013-10-19 00:09:25 -07001784
1785 directory = os.path.dirname(filename) or '.'
1786
1787 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001788 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001789 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1790 with open(tmpfilename, "wb") as f:
1791 f.write(bytes)
1792 os.replace(tmpfilename, output or filename)
1793
1794
Larry Hastings581ee362014-01-28 05:00:08 -08001795def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001796 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001797 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1798 if length:
1799 s = s[:length]
1800 return s
Larry Hastings31826802013-10-19 00:09:25 -07001801
1802
1803
1804
1805class PythonParser:
1806 def __init__(self, clinic):
1807 pass
1808
1809 def parse(self, block):
1810 s = io.StringIO()
1811 with OverrideStdioWith(s):
1812 exec(block.input)
1813 block.output = s.getvalue()
1814
1815
1816class Module:
1817 def __init__(self, name, module=None):
1818 self.name = name
1819 self.module = self.parent = module
1820
1821 self.modules = collections.OrderedDict()
1822 self.classes = collections.OrderedDict()
1823 self.functions = []
1824
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001825 def __repr__(self):
1826 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1827
Larry Hastings31826802013-10-19 00:09:25 -07001828class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001829 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001830 self.name = name
1831 self.module = module
1832 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001833 self.typedef = typedef
1834 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001835 self.parent = cls or module
1836
1837 self.classes = collections.OrderedDict()
1838 self.functions = []
1839
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001840 def __repr__(self):
1841 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1842
Larry Hastings8666e652014-01-12 14:12:59 -08001843unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001844
Larry Hastings8666e652014-01-12 14:12:59 -08001845__abs__
1846__add__
1847__and__
1848__bytes__
1849__call__
1850__complex__
1851__delitem__
1852__divmod__
1853__eq__
1854__float__
1855__floordiv__
1856__ge__
1857__getattr__
1858__getattribute__
1859__getitem__
1860__gt__
1861__hash__
1862__iadd__
1863__iand__
Larry Hastings8666e652014-01-12 14:12:59 -08001864__ifloordiv__
1865__ilshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02001866__imatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08001867__imod__
1868__imul__
1869__index__
1870__int__
1871__invert__
1872__ior__
1873__ipow__
1874__irshift__
1875__isub__
1876__iter__
1877__itruediv__
1878__ixor__
1879__le__
1880__len__
1881__lshift__
1882__lt__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02001883__matmul__
Larry Hastings8666e652014-01-12 14:12:59 -08001884__mod__
1885__mul__
1886__neg__
1887__new__
1888__next__
1889__or__
1890__pos__
1891__pow__
1892__radd__
1893__rand__
1894__rdivmod__
1895__repr__
1896__rfloordiv__
1897__rlshift__
Serhiy Storchakac2ccce72015-03-12 22:01:30 +02001898__rmatmul__
Larry Hastings8666e652014-01-12 14:12:59 -08001899__rmod__
1900__rmul__
1901__ror__
1902__round__
1903__rpow__
1904__rrshift__
1905__rshift__
1906__rsub__
1907__rtruediv__
1908__rxor__
1909__setattr__
1910__setitem__
1911__str__
1912__sub__
1913__truediv__
1914__xor__
1915
1916""".strip().split())
1917
1918
Larry Hastings5c661892014-01-24 06:17:25 -08001919INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
1920INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
1921""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07001922
1923class Function:
1924 """
1925 Mutable duck type for inspect.Function.
1926
1927 docstring - a str containing
1928 * embedded line breaks
1929 * text outdented to the left margin
1930 * no trailing whitespace.
1931 It will always be true that
1932 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1933 """
1934
1935 def __init__(self, parameters=None, *, name,
1936 module, cls=None, c_basename=None,
1937 full_name=None,
1938 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08001939 docstring=None, kind=CALLABLE, coexist=False,
Larry Hastings2623c8c2014-02-08 22:15:29 -08001940 docstring_only=False):
Larry Hastings31826802013-10-19 00:09:25 -07001941 self.parameters = parameters or collections.OrderedDict()
1942 self.return_annotation = return_annotation
1943 self.name = name
1944 self.full_name = full_name
1945 self.module = module
1946 self.cls = cls
1947 self.parent = cls or module
1948 self.c_basename = c_basename
1949 self.return_converter = return_converter
1950 self.docstring = docstring or ''
1951 self.kind = kind
1952 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001953 self.self_converter = None
Larry Hastings2623c8c2014-02-08 22:15:29 -08001954 # docstring_only means "don't generate a machine-readable
1955 # signature, just a normal docstring". it's True for
1956 # functions with optional groups because we can't represent
1957 # those accurately with inspect.Signature in 3.4.
1958 self.docstring_only = docstring_only
Larry Hastingsebdcb502013-11-23 14:54:00 -08001959
Larry Hastings7726ac92014-01-31 22:03:12 -08001960 self.rendered_parameters = None
1961
1962 __render_parameters__ = None
1963 @property
1964 def render_parameters(self):
1965 if not self.__render_parameters__:
1966 self.__render_parameters__ = l = []
1967 for p in self.parameters.values():
1968 p = p.copy()
1969 p.converter.pre_render()
1970 l.append(p)
1971 return self.__render_parameters__
1972
Larry Hastingsebdcb502013-11-23 14:54:00 -08001973 @property
1974 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001975 if self.kind in (METHOD_INIT, METHOD_NEW):
1976 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001977 flags = []
1978 if self.kind == CLASS_METHOD:
1979 flags.append('METH_CLASS')
1980 elif self.kind == STATIC_METHOD:
1981 flags.append('METH_STATIC')
1982 else:
1983 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1984 if self.coexist:
1985 flags.append('METH_COEXIST')
1986 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001987
1988 def __repr__(self):
1989 return '<clinic.Function ' + self.name + '>'
1990
Larry Hastings7726ac92014-01-31 22:03:12 -08001991 def copy(self, **overrides):
1992 kwargs = {
1993 'name': self.name, 'module': self.module, 'parameters': self.parameters,
1994 'cls': self.cls, 'c_basename': self.c_basename,
1995 'full_name': self.full_name,
1996 'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
1997 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
Larry Hastings2623c8c2014-02-08 22:15:29 -08001998 'docstring_only': self.docstring_only,
Larry Hastings7726ac92014-01-31 22:03:12 -08001999 }
2000 kwargs.update(overrides)
2001 f = Function(**kwargs)
2002
2003 parameters = collections.OrderedDict()
2004 for name, value in f.parameters.items():
2005 value = value.copy(function=f)
2006 parameters[name] = value
2007 f.parameters = parameters
2008 return f
2009
Larry Hastings31826802013-10-19 00:09:25 -07002010
2011class Parameter:
2012 """
2013 Mutable duck type of inspect.Parameter.
2014 """
2015
2016 def __init__(self, name, kind, *, default=_empty,
2017 function, converter, annotation=_empty,
2018 docstring=None, group=0):
2019 self.name = name
2020 self.kind = kind
2021 self.default = default
2022 self.function = function
2023 self.converter = converter
2024 self.annotation = annotation
2025 self.docstring = docstring or ''
2026 self.group = group
2027
2028 def __repr__(self):
2029 return '<clinic.Parameter ' + self.name + '>'
2030
2031 def is_keyword_only(self):
2032 return self.kind == inspect.Parameter.KEYWORD_ONLY
2033
Larry Hastings2623c8c2014-02-08 22:15:29 -08002034 def is_positional_only(self):
2035 return self.kind == inspect.Parameter.POSITIONAL_ONLY
2036
Larry Hastings7726ac92014-01-31 22:03:12 -08002037 def copy(self, **overrides):
2038 kwargs = {
2039 'name': self.name, 'kind': self.kind, 'default':self.default,
2040 'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
2041 'docstring': self.docstring, 'group': self.group,
2042 }
2043 kwargs.update(overrides)
2044 if 'converter' not in overrides:
2045 converter = copy.copy(self.converter)
2046 converter.function = kwargs['function']
2047 kwargs['converter'] = converter
2048 return Parameter(**kwargs)
2049
2050
2051
2052class LandMine:
2053 # try to access any
2054 def __init__(self, message):
2055 self.__message__ = message
2056
2057 def __repr__(self):
2058 return '<LandMine ' + repr(self.__message__) + ">"
2059
2060 def __getattribute__(self, name):
2061 if name in ('__repr__', '__message__'):
2062 return super().__getattribute__(name)
2063 # raise RuntimeError(repr(name))
2064 fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__)
Larry Hastings31826802013-10-19 00:09:25 -07002065
Larry Hastings31826802013-10-19 00:09:25 -07002066
2067def add_c_converter(f, name=None):
2068 if not name:
2069 name = f.__name__
2070 if not name.endswith('_converter'):
2071 return f
2072 name = name[:-len('_converter')]
2073 converters[name] = f
2074 return f
2075
2076def add_default_legacy_c_converter(cls):
2077 # automatically add converter for default format unit
2078 # (but without stomping on the existing one if it's already
2079 # set, in case you subclass)
Larry Hastingsf1503782014-06-11 04:31:29 -07002080 if ((cls.format_unit not in ('O&', '')) and
Larry Hastings31826802013-10-19 00:09:25 -07002081 (cls.format_unit not in legacy_converters)):
2082 legacy_converters[cls.format_unit] = cls
2083 return cls
2084
2085def add_legacy_c_converter(format_unit, **kwargs):
2086 """
2087 Adds a legacy converter.
2088 """
2089 def closure(f):
2090 if not kwargs:
2091 added_f = f
2092 else:
2093 added_f = functools.partial(f, **kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002094 if format_unit:
2095 legacy_converters[format_unit] = added_f
Larry Hastings31826802013-10-19 00:09:25 -07002096 return f
2097 return closure
2098
2099class CConverterAutoRegister(type):
2100 def __init__(cls, name, bases, classdict):
2101 add_c_converter(cls)
2102 add_default_legacy_c_converter(cls)
2103
2104class CConverter(metaclass=CConverterAutoRegister):
2105 """
2106 For the init function, self, name, function, and default
2107 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002108 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002109 """
2110
Larry Hastings7726ac92014-01-31 22:03:12 -08002111 # The C name to use for this variable.
2112 name = None
2113
2114 # The Python name to use for this variable.
2115 py_name = None
2116
Larry Hastings78cf85c2014-01-04 12:44:57 -08002117 # The C type to use for this variable.
2118 # 'type' should be a Python string specifying the type, e.g. "int".
2119 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002120 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002121
2122 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002123 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002124 # Or the magic value "unknown" if this value is a cannot be evaluated
2125 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2126 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002127 default = unspecified
2128
Larry Hastings4a55fc52014-01-12 11:09:57 -08002129 # If not None, default must be isinstance() of this type.
2130 # (You can also specify a tuple of types.)
2131 default_type = None
2132
Larry Hastings31826802013-10-19 00:09:25 -07002133 # "default" converted into a C value, as a string.
2134 # Or None if there is no default.
2135 c_default = None
2136
Larry Hastings2a727912014-01-16 11:32:01 -08002137 # "default" converted into a Python value, as a string.
2138 # Or None if there is no default.
2139 py_default = None
2140
Larry Hastingsabc716b2013-11-20 09:13:52 -08002141 # The default value used to initialize the C variable when
2142 # there is no default, but not specifying a default may
2143 # result in an "uninitialized variable" warning. This can
2144 # easily happen when using option groups--although
2145 # properly-written code won't actually use the variable,
2146 # the variable does get passed in to the _impl. (Ah, if
2147 # only dataflow analysis could inline the static function!)
2148 #
2149 # This value is specified as a string.
2150 # Every non-abstract subclass should supply a valid value.
2151 c_ignored_default = 'NULL'
2152
Larry Hastings31826802013-10-19 00:09:25 -07002153 # The C converter *function* to be used, if any.
2154 # (If this is not None, format_unit must be 'O&'.)
2155 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002156
Larry Hastings78cf85c2014-01-04 12:44:57 -08002157 # Should Argument Clinic add a '&' before the name of
2158 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002159 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002160
2161 # Should Argument Clinic add a '&' before the name of
2162 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002163 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002164
2165 #############################################################
2166 #############################################################
2167 ## You shouldn't need to read anything below this point to ##
2168 ## write your own converter functions. ##
2169 #############################################################
2170 #############################################################
2171
2172 # The "format unit" to specify for this variable when
2173 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2174 # Custom converters should always use the default value of 'O&'.
2175 format_unit = 'O&'
2176
2177 # What encoding do we want for this variable? Only used
2178 # by format units starting with 'e'.
2179 encoding = None
2180
Larry Hastings77561cc2014-01-07 12:13:13 -08002181 # Should this object be required to be a subclass of a specific type?
2182 # If not None, should be a string representing a pointer to a
2183 # PyTypeObject (e.g. "&PyUnicode_Type").
2184 # Only used by the 'O!' format unit (and the "object" converter).
2185 subclass_of = None
2186
Larry Hastings78cf85c2014-01-04 12:44:57 -08002187 # Do we want an adjacent '_length' variable for this variable?
2188 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002189 length = False
2190
Larry Hastings5c661892014-01-24 06:17:25 -08002191 # Should we show this parameter in the generated
2192 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002193 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002194 show_in_signature = True
2195
2196 # Overrides the name used in a text signature.
2197 # The name used for a "self" parameter must be one of
2198 # self, type, or module; however users can set their own.
2199 # This lets the self_converter overrule the user-settable
2200 # name, *just* for the text signature.
2201 # Only set by self_converter.
2202 signature_name = None
2203
2204 # keep in sync with self_converter.__init__!
Larry Hastings7726ac92014-01-31 22:03:12 -08002205 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 -07002206 self.name = name
Larry Hastings7726ac92014-01-31 22:03:12 -08002207 self.py_name = py_name
Larry Hastings31826802013-10-19 00:09:25 -07002208
2209 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002210 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002211 if isinstance(self.default_type, type):
2212 types_str = self.default_type.__name__
2213 else:
2214 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2215 fail("{}: default value {!r} for field {} is not of type {}".format(
2216 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002217 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002218
Larry Hastingsb4705752014-01-18 21:54:15 -08002219 if c_default:
2220 self.c_default = c_default
2221 if py_default:
2222 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002223
Larry Hastings31826802013-10-19 00:09:25 -07002224 if annotation != unspecified:
2225 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings7726ac92014-01-31 22:03:12 -08002226
2227 # this is deliberate, to prevent you from caching information
2228 # about the function in the init.
2229 # (that breaks if we get cloned.)
2230 # so after this change we will noisily fail.
2231 self.function = LandMine("Don't access members of self.function inside converter_init!")
Larry Hastings31826802013-10-19 00:09:25 -07002232 self.converter_init(**kwargs)
Larry Hastings7726ac92014-01-31 22:03:12 -08002233 self.function = function
Larry Hastings31826802013-10-19 00:09:25 -07002234
2235 def converter_init(self):
2236 pass
2237
2238 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002239 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002240
Larry Hastings5c661892014-01-24 06:17:25 -08002241 def _render_self(self, parameter, data):
2242 self.parameter = parameter
2243 original_name = self.name
2244 name = ensure_legal_c_identifier(original_name)
2245
2246 # impl_arguments
2247 s = ("&" if self.impl_by_reference else "") + name
2248 data.impl_arguments.append(s)
2249 if self.length:
2250 data.impl_arguments.append(self.length_name())
2251
2252 # impl_parameters
2253 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2254 if self.length:
2255 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2256
2257 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002258 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002259 original_name = self.name
2260 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002261
2262 # declarations
2263 d = self.declaration()
2264 data.declarations.append(d)
2265
2266 # initializers
2267 initializers = self.initialize()
2268 if initializers:
2269 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2270
Larry Hastingsc2047262014-01-25 20:43:29 -08002271 # modifications
2272 modifications = self.modify()
2273 if modifications:
2274 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2275
Larry Hastings31826802013-10-19 00:09:25 -07002276 # keywords
Larry Hastings7726ac92014-01-31 22:03:12 -08002277 data.keywords.append(parameter.name)
Larry Hastings31826802013-10-19 00:09:25 -07002278
2279 # format_units
2280 if self.is_optional() and '|' not in data.format_units:
2281 data.format_units.append('|')
2282 if parameter.is_keyword_only() and '$' not in data.format_units:
2283 data.format_units.append('$')
2284 data.format_units.append(self.format_unit)
2285
2286 # parse_arguments
2287 self.parse_argument(data.parse_arguments)
2288
Larry Hastings31826802013-10-19 00:09:25 -07002289 # cleanup
2290 cleanup = self.cleanup()
2291 if cleanup:
2292 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2293
Larry Hastings5c661892014-01-24 06:17:25 -08002294 def render(self, parameter, data):
2295 """
2296 parameter is a clinic.Parameter instance.
2297 data is a CRenderData instance.
2298 """
2299 self._render_self(parameter, data)
2300 self._render_non_self(parameter, data)
2301
Larry Hastingsebdcb502013-11-23 14:54:00 -08002302 def length_name(self):
2303 """Computes the name of the associated "length" variable."""
2304 if not self.length:
2305 return None
2306 return ensure_legal_c_identifier(self.name) + "_length"
2307
Larry Hastings31826802013-10-19 00:09:25 -07002308 # Why is this one broken out separately?
2309 # For "positional-only" function parsing,
2310 # which generates a bunch of PyArg_ParseTuple calls.
2311 def parse_argument(self, list):
2312 assert not (self.converter and self.encoding)
2313 if self.format_unit == 'O&':
2314 assert self.converter
2315 list.append(self.converter)
2316
2317 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002318 list.append(c_repr(self.encoding))
2319 elif self.subclass_of:
2320 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002321
Larry Hastingsebdcb502013-11-23 14:54:00 -08002322 legal_name = ensure_legal_c_identifier(self.name)
2323 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002324 list.append(s)
2325
Larry Hastingsebdcb502013-11-23 14:54:00 -08002326 if self.length:
2327 list.append("&" + self.length_name())
2328
Larry Hastings31826802013-10-19 00:09:25 -07002329 #
2330 # All the functions after here are intended as extension points.
2331 #
2332
2333 def simple_declaration(self, by_reference=False):
2334 """
2335 Computes the basic declaration of the variable.
2336 Used in computing the prototype declaration and the
2337 variable declaration.
2338 """
2339 prototype = [self.type]
2340 if by_reference or not self.type.endswith('*'):
2341 prototype.append(" ")
2342 if by_reference:
2343 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002344 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002345 return "".join(prototype)
2346
2347 def declaration(self):
2348 """
2349 The C statement to declare this variable.
2350 """
2351 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002352 default = self.c_default
2353 if not default and self.parameter.group:
2354 default = self.c_ignored_default
2355 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002356 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002357 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002358 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002359 if self.length:
2360 declaration.append('\nPy_ssize_clean_t ')
2361 declaration.append(self.length_name())
2362 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08002363 s = "".join(declaration)
2364 # double up curly-braces, this string will be used
2365 # as part of a format_map() template later
2366 s = s.replace("{", "{{")
2367 s = s.replace("}", "}}")
2368 return s
Larry Hastings31826802013-10-19 00:09:25 -07002369
2370 def initialize(self):
2371 """
2372 The C statements required to set up this variable before parsing.
2373 Returns a string containing this code indented at column 0.
2374 If no initialization is necessary, returns an empty string.
2375 """
2376 return ""
2377
Larry Hastingsc2047262014-01-25 20:43:29 -08002378 def modify(self):
2379 """
2380 The C statements required to modify this variable after parsing.
2381 Returns a string containing this code indented at column 0.
2382 If no initialization is necessary, returns an empty string.
2383 """
2384 return ""
2385
Larry Hastings31826802013-10-19 00:09:25 -07002386 def cleanup(self):
2387 """
2388 The C statements required to clean up after this variable.
2389 Returns a string containing this code indented at column 0.
2390 If no cleanup is necessary, returns an empty string.
2391 """
2392 return ""
2393
Larry Hastings7726ac92014-01-31 22:03:12 -08002394 def pre_render(self):
2395 """
2396 A second initialization function, like converter_init,
2397 called just before rendering.
2398 You are permitted to examine self.function here.
2399 """
2400 pass
2401
Larry Hastings31826802013-10-19 00:09:25 -07002402
2403class bool_converter(CConverter):
2404 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002405 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002406 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002407 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002408
2409 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002410 if self.default is not unspecified:
2411 self.default = bool(self.default)
2412 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002413
2414class char_converter(CConverter):
2415 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002416 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07002417 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002418 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002419
Larry Hastings4a55fc52014-01-12 11:09:57 -08002420 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002421 if isinstance(self.default, str) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002422 fail("char_converter: illegal default value " + repr(self.default))
2423
2424
Larry Hastings31826802013-10-19 00:09:25 -07002425@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002426class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002427 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002428 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002429 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002430 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002431
2432 def converter_init(self, *, bitwise=False):
2433 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002434 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002435
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002436class byte_converter(unsigned_char_converter): pass
2437
Larry Hastings31826802013-10-19 00:09:25 -07002438class short_converter(CConverter):
2439 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002440 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002441 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002442 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002443
2444class unsigned_short_converter(CConverter):
2445 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002446 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002447 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002448 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002449
2450 def converter_init(self, *, bitwise=False):
2451 if not bitwise:
2452 fail("Unsigned shorts must be bitwise (for now).")
2453
Larry Hastingsebdcb502013-11-23 14:54:00 -08002454@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07002455class int_converter(CConverter):
2456 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002457 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002458 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002459 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002460
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002461 def converter_init(self, *, types='int', type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002462 if types == 'str':
2463 self.format_unit = 'C'
2464 elif types != 'int':
2465 fail("int_converter: illegal 'types' argument")
Larry Hastingsdfbeb162014-10-13 10:39:41 +01002466 if type != None:
2467 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002468
2469class unsigned_int_converter(CConverter):
2470 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002471 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002472 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002473 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002474
2475 def converter_init(self, *, bitwise=False):
2476 if not bitwise:
2477 fail("Unsigned ints must be bitwise (for now).")
2478
2479class long_converter(CConverter):
2480 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002481 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002482 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002483 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002484
2485class unsigned_long_converter(CConverter):
2486 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002487 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002488 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002489 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002490
2491 def converter_init(self, *, bitwise=False):
2492 if not bitwise:
2493 fail("Unsigned longs must be bitwise (for now).")
2494
2495class PY_LONG_LONG_converter(CConverter):
2496 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002497 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002498 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002499 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002500
2501class unsigned_PY_LONG_LONG_converter(CConverter):
2502 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002503 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002504 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002505 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002506
2507 def converter_init(self, *, bitwise=False):
2508 if not bitwise:
2509 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
2510
2511class Py_ssize_t_converter(CConverter):
2512 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002513 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002514 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002515 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002516
2517
2518class float_converter(CConverter):
2519 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002520 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002521 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002522 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002523
2524class double_converter(CConverter):
2525 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002526 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002527 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002528 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002529
2530
2531class Py_complex_converter(CConverter):
2532 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002533 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002534 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002535 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002536
2537
2538class object_converter(CConverter):
2539 type = 'PyObject *'
2540 format_unit = 'O'
2541
Larry Hastings4a55fc52014-01-12 11:09:57 -08002542 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2543 if converter:
2544 if subclass_of:
2545 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2546 self.format_unit = 'O&'
2547 self.converter = converter
2548 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002549 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002550 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002551
Larry Hastings77561cc2014-01-07 12:13:13 -08002552 if type is not None:
2553 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002554
2555
Larry Hastingsebdcb502013-11-23 14:54:00 -08002556@add_legacy_c_converter('s#', length=True)
Larry Hastings2a727912014-01-16 11:32:01 -08002557@add_legacy_c_converter('y', types="bytes")
2558@add_legacy_c_converter('y#', types="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002559@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002560@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002561class str_converter(CConverter):
2562 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002563 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002564 format_unit = 's'
2565
Larry Hastingsebdcb502013-11-23 14:54:00 -08002566 def converter_init(self, *, encoding=None, types="str",
2567 length=False, nullable=False, zeroes=False):
2568
2569 types = set(types.strip().split())
Serhiy Storchaka5d438332014-11-15 13:30:42 +02002570 bytes_type = {"bytes"}
2571 str_type = {"str"}
2572 all_3_type = {"bytearray"} | bytes_type | str_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002573 is_bytes = types == bytes_type
2574 is_str = types == str_type
2575 is_all_3 = types == all_3_type
2576
2577 self.length = bool(length)
2578 format_unit = None
2579
2580 if encoding:
2581 self.encoding = encoding
2582
2583 if is_str and not (length or zeroes or nullable):
2584 format_unit = 'es'
2585 elif is_all_3 and not (length or zeroes or nullable):
2586 format_unit = 'et'
2587 elif is_str and length and zeroes and not nullable:
2588 format_unit = 'es#'
2589 elif is_all_3 and length and not (nullable or zeroes):
2590 format_unit = 'et#'
2591
2592 if format_unit.endswith('#'):
Larry Hastings5c661892014-01-24 06:17:25 -08002593 fail("Sorry: code using format unit ", repr(format_unit), "probably doesn't work properly yet.\nGive Larry your test case and he'll it.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002594 # TODO set pointer to NULL
2595 # TODO add cleanup for buffer
2596 pass
2597
2598 else:
2599 if zeroes:
2600 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
2601
2602 if is_bytes and not (nullable or length):
2603 format_unit = 'y'
2604 elif is_bytes and length and not nullable:
2605 format_unit = 'y#'
2606 elif is_str and not (nullable or length):
2607 format_unit = 's'
2608 elif is_str and length and not nullable:
2609 format_unit = 's#'
2610 elif is_str and nullable and not length:
2611 format_unit = 'z'
2612 elif is_str and nullable and length:
2613 format_unit = 'z#'
2614
2615 if not format_unit:
2616 fail("str_converter: illegal combination of arguments")
2617 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002618
2619
2620class PyBytesObject_converter(CConverter):
2621 type = 'PyBytesObject *'
2622 format_unit = 'S'
2623
2624class PyByteArrayObject_converter(CConverter):
2625 type = 'PyByteArrayObject *'
2626 format_unit = 'Y'
2627
2628class unicode_converter(CConverter):
2629 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002630 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002631 format_unit = 'U'
2632
Larry Hastingsebdcb502013-11-23 14:54:00 -08002633@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002634@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002635@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002636class Py_UNICODE_converter(CConverter):
2637 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002638 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002639 format_unit = 'u'
2640
Larry Hastingsebdcb502013-11-23 14:54:00 -08002641 def converter_init(self, *, nullable=False, length=False):
2642 format_unit = 'Z' if nullable else 'u'
2643 if length:
2644 format_unit += '#'
2645 self.length = True
2646 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002647
Larry Hastingsebdcb502013-11-23 14:54:00 -08002648#
2649# We define three string conventions for buffer types in the 'types' argument:
2650# 'buffer' : any object supporting the buffer interface
2651# 'rwbuffer': any object supporting the buffer interface, but must be writeable
2652# 'robuffer': any object supporting the buffer interface, but must not be writeable
2653#
2654@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
2655@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
2656@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07002657class Py_buffer_converter(CConverter):
2658 type = 'Py_buffer'
2659 format_unit = 'y*'
2660 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002661 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002662
Larry Hastingsebdcb502013-11-23 14:54:00 -08002663 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002664 if self.default not in (unspecified, None):
2665 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08002666 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002667 types = set(types.strip().split())
Serhiy Storchaka5d438332014-11-15 13:30:42 +02002668 bytes_type = {'bytes'}
2669 bytearray_type = {'bytearray'}
2670 buffer_type = {'buffer'}
2671 rwbuffer_type = {'rwbuffer'}
2672 robuffer_type = {'robuffer'}
2673 str_type = {'str'}
Larry Hastingsebdcb502013-11-23 14:54:00 -08002674 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
2675
2676 format_unit = None
2677 if types == (str_type | bytes_bytearray_buffer_type):
2678 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07002679 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002680 if nullable:
2681 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
2682 elif types == (bytes_bytearray_buffer_type):
2683 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002684 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002685 format_unit = 'w*'
2686 if not format_unit:
2687 fail("Py_buffer_converter: illegal combination of arguments")
2688
2689 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002690
2691 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002692 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002693 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002694
2695
Larry Hastings5c661892014-01-24 06:17:25 -08002696def correct_name_for_self(f):
2697 if f.kind in (CALLABLE, METHOD_INIT):
2698 if f.cls:
2699 return "PyObject *", "self"
2700 return "PyModuleDef *", "module"
2701 if f.kind == STATIC_METHOD:
2702 return "void *", "null"
2703 if f.kind in (CLASS_METHOD, METHOD_NEW):
2704 return "PyTypeObject *", "type"
2705 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2706
Larry Hastingsc2047262014-01-25 20:43:29 -08002707def required_type_for_self_for_parser(f):
2708 type, _ = correct_name_for_self(f)
2709 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2710 return type
2711 return None
2712
Larry Hastings5c661892014-01-24 06:17:25 -08002713
Larry Hastingsebdcb502013-11-23 14:54:00 -08002714class self_converter(CConverter):
2715 """
2716 A special-case converter:
2717 this is the default converter used for "self".
2718 """
Larry Hastings5c661892014-01-24 06:17:25 -08002719 type = None
2720 format_unit = ''
2721
Larry Hastings78cf85c2014-01-04 12:44:57 -08002722 def converter_init(self, *, type=None):
Larry Hastings7726ac92014-01-31 22:03:12 -08002723 self.specified_type = type
2724
2725 def pre_render(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002726 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002727 default_type, default_name = correct_name_for_self(f)
2728 self.signature_name = default_name
Larry Hastings7726ac92014-01-31 22:03:12 -08002729 self.type = self.specified_type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002730
Larry Hastings5c661892014-01-24 06:17:25 -08002731 kind = self.function.kind
2732 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2733
2734 if (kind == STATIC_METHOD) or new_or_init:
2735 self.show_in_signature = False
2736
2737 # tp_new (METHOD_NEW) functions are of type newfunc:
2738 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2739 # PyTypeObject is a typedef for struct _typeobject.
2740 #
2741 # tp_init (METHOD_INIT) functions are of type initproc:
2742 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2743 #
2744 # All other functions generated by Argument Clinic are stored in
2745 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2746 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2747 # However! We habitually cast these functions to PyCFunction,
2748 # since functions that accept keyword arguments don't fit this signature
2749 # but are stored there anyway. So strict type equality isn't important
2750 # for these functions.
2751 #
2752 # So:
2753 #
2754 # * The name of the first parameter to the impl and the parsing function will always
2755 # be self.name.
2756 #
2757 # * The type of the first parameter to the impl will always be of self.type.
2758 #
2759 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2760 # * The type of the first parameter to the parsing function is also self.type.
2761 # This means that if you step into the parsing function, your "self" parameter
2762 # is of the correct type, which may make debugging more pleasant.
2763 #
2764 # * Else if the function is tp_new (METHOD_NEW):
2765 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2766 # so the type signature of the function call is an exact match.
2767 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2768 # in the impl call.
2769 #
2770 # * Else if the function is tp_init (METHOD_INIT):
2771 # * The type of the first parameter to the parsing function is "PyObject *",
2772 # so the type signature of the function call is an exact match.
2773 # * If self.type != "PyObject *", we cast the first parameter to self.type
2774 # in the impl call.
2775
2776 @property
2777 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002778 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002779
Larry Hastingsebdcb502013-11-23 14:54:00 -08002780 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002781 """
2782 parameter is a clinic.Parameter instance.
2783 data is a CRenderData instance.
2784 """
2785 if self.function.kind == STATIC_METHOD:
2786 return
2787
2788 self._render_self(parameter, data)
2789
2790 if self.type != self.parser_type:
2791 # insert cast to impl_argument[0], aka self.
2792 # we know we're in the first slot in all the CRenderData lists,
2793 # because we render parameters in order, and self is always first.
2794 assert len(data.impl_arguments) == 1
2795 assert data.impl_arguments[0] == self.name
2796 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
2797
2798 def set_template_dict(self, template_dict):
2799 template_dict['self_name'] = self.name
2800 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08002801 kind = self.function.kind
2802 cls = self.function.cls
2803
2804 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
2805 if kind == METHOD_NEW:
2806 passed_in_type = self.name
2807 else:
2808 passed_in_type = 'Py_TYPE({})'.format(self.name)
2809
2810 line = '({passed_in_type} == {type_object}) &&\n '
2811 d = {
2812 'type_object': self.function.cls.type_object,
2813 'passed_in_type': passed_in_type
2814 }
2815 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002816
Larry Hastings31826802013-10-19 00:09:25 -07002817
2818
2819def add_c_return_converter(f, name=None):
2820 if not name:
2821 name = f.__name__
2822 if not name.endswith('_return_converter'):
2823 return f
2824 name = name[:-len('_return_converter')]
2825 return_converters[name] = f
2826 return f
2827
2828
2829class CReturnConverterAutoRegister(type):
2830 def __init__(cls, name, bases, classdict):
2831 add_c_return_converter(cls)
2832
2833class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2834
Larry Hastings78cf85c2014-01-04 12:44:57 -08002835 # The C type to use for this variable.
2836 # 'type' should be a Python string specifying the type, e.g. "int".
2837 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002838 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002839
2840 # The Python default value for this parameter, as a Python value.
2841 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002842 default = None
2843
Larry Hastings2a727912014-01-16 11:32:01 -08002844 def __init__(self, *, py_default=None, **kwargs):
2845 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002846 try:
2847 self.return_converter_init(**kwargs)
2848 except TypeError as e:
2849 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2850 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2851
2852 def return_converter_init(self):
2853 pass
2854
2855 def declare(self, data, name="_return_value"):
2856 line = []
2857 add = line.append
2858 add(self.type)
2859 if not self.type.endswith('*'):
2860 add(' ')
2861 add(name + ';')
2862 data.declarations.append(''.join(line))
2863 data.return_value = name
2864
2865 def err_occurred_if(self, expr, data):
2866 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2867
2868 def err_occurred_if_null_pointer(self, variable, data):
2869 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2870
2871 def render(self, function, data):
2872 """
2873 function is a clinic.Function instance.
2874 data is a CRenderData instance.
2875 """
2876 pass
2877
2878add_c_return_converter(CReturnConverter, 'object')
2879
Larry Hastings78cf85c2014-01-04 12:44:57 -08002880class NoneType_return_converter(CReturnConverter):
2881 def render(self, function, data):
2882 self.declare(data)
2883 data.return_conversion.append('''
2884if (_return_value != Py_None)
2885 goto exit;
2886return_value = Py_None;
2887Py_INCREF(Py_None);
2888'''.strip())
2889
Larry Hastings4a55fc52014-01-12 11:09:57 -08002890class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002891 type = 'int'
2892
2893 def render(self, function, data):
2894 self.declare(data)
2895 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002896 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002897
2898class long_return_converter(CReturnConverter):
2899 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002900 conversion_fn = 'PyLong_FromLong'
2901 cast = ''
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10002902 unsigned_cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002903
2904 def render(self, function, data):
2905 self.declare(data)
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10002906 self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
Larry Hastings31826802013-10-19 00:09:25 -07002907 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002908 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002909
Larry Hastings4a55fc52014-01-12 11:09:57 -08002910class int_return_converter(long_return_converter):
2911 type = 'int'
2912 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002913
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002914class init_return_converter(long_return_converter):
2915 """
2916 Special return converter for __init__ functions.
2917 """
2918 type = 'int'
2919 cast = '(long)'
2920
2921 def render(self, function, data):
2922 pass
2923
Larry Hastings4a55fc52014-01-12 11:09:57 -08002924class unsigned_long_return_converter(long_return_converter):
2925 type = 'unsigned long'
2926 conversion_fn = 'PyLong_FromUnsignedLong'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10002927 unsigned_cast = '(unsigned long)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002928
2929class unsigned_int_return_converter(unsigned_long_return_converter):
2930 type = 'unsigned int'
2931 cast = '(unsigned long)'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10002932 unsigned_cast = '(unsigned int)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002933
2934class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002935 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002936 conversion_fn = 'PyLong_FromSsize_t'
2937
2938class size_t_return_converter(long_return_converter):
2939 type = 'size_t'
2940 conversion_fn = 'PyLong_FromSize_t'
Larry Hastingsa73cb8a2014-08-05 19:55:21 +10002941 unsigned_cast = '(size_t)'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002942
2943
2944class double_return_converter(CReturnConverter):
2945 type = 'double'
2946 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002947
2948 def render(self, function, data):
2949 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002950 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002951 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002952 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2953
2954class float_return_converter(double_return_converter):
2955 type = 'float'
2956 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002957
2958
2959class DecodeFSDefault_return_converter(CReturnConverter):
2960 type = 'char *'
2961
2962 def render(self, function, data):
2963 self.declare(data)
2964 self.err_occurred_if_null_pointer("_return_value", data)
2965 data.return_conversion.append(
2966 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2967
2968
2969class IndentStack:
2970 def __init__(self):
2971 self.indents = []
2972 self.margin = None
2973
2974 def _ensure(self):
2975 if not self.indents:
2976 fail('IndentStack expected indents, but none are defined.')
2977
2978 def measure(self, line):
2979 """
2980 Returns the length of the line's margin.
2981 """
2982 if '\t' in line:
Larry Hastings2623c8c2014-02-08 22:15:29 -08002983 fail('Tab characters are illegal in the Argument Clinic DSL.')
Larry Hastings31826802013-10-19 00:09:25 -07002984 stripped = line.lstrip()
2985 if not len(stripped):
2986 # we can't tell anything from an empty line
2987 # so just pretend it's indented like our current indent
2988 self._ensure()
2989 return self.indents[-1]
2990 return len(line) - len(stripped)
2991
2992 def infer(self, line):
2993 """
2994 Infer what is now the current margin based on this line.
2995 Returns:
2996 1 if we have indented (or this is the first margin)
2997 0 if the margin has not changed
2998 -N if we have dedented N times
2999 """
3000 indent = self.measure(line)
3001 margin = ' ' * indent
3002 if not self.indents:
3003 self.indents.append(indent)
3004 self.margin = margin
3005 return 1
3006 current = self.indents[-1]
3007 if indent == current:
3008 return 0
3009 if indent > current:
3010 self.indents.append(indent)
3011 self.margin = margin
3012 return 1
3013 # indent < current
3014 if indent not in self.indents:
3015 fail("Illegal outdent.")
3016 outdent_count = 0
3017 while indent != current:
3018 self.indents.pop()
3019 current = self.indents[-1]
3020 outdent_count -= 1
3021 self.margin = margin
3022 return outdent_count
3023
3024 @property
3025 def depth(self):
3026 """
3027 Returns how many margins are currently defined.
3028 """
3029 return len(self.indents)
3030
3031 def indent(self, line):
3032 """
3033 Indents a line by the currently defined margin.
3034 """
3035 return self.margin + line
3036
3037 def dedent(self, line):
3038 """
3039 Dedents a line by the currently defined margin.
3040 (The inverse of 'indent'.)
3041 """
3042 margin = self.margin
3043 indent = self.indents[-1]
3044 if not line.startswith(margin):
3045 fail('Cannot dedent, line does not start with the previous margin:')
3046 return line[indent:]
3047
3048
3049class DSLParser:
3050 def __init__(self, clinic):
3051 self.clinic = clinic
3052
3053 self.directives = {}
3054 for name in dir(self):
3055 # functions that start with directive_ are added to directives
3056 _, s, key = name.partition("directive_")
3057 if s:
3058 self.directives[key] = getattr(self, name)
3059
3060 # functions that start with at_ are too, with an @ in front
3061 _, s, key = name.partition("at_")
3062 if s:
3063 self.directives['@' + key] = getattr(self, name)
3064
3065 self.reset()
3066
3067 def reset(self):
3068 self.function = None
3069 self.state = self.state_dsl_start
3070 self.parameter_indent = None
3071 self.keyword_only = False
3072 self.group = 0
3073 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08003074 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07003075 self.indent = IndentStack()
3076 self.kind = CALLABLE
3077 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08003078 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08003079 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07003080
Larry Hastingsebdcb502013-11-23 14:54:00 -08003081 def directive_version(self, required):
3082 global version
3083 if version_comparitor(version, required) < 0:
3084 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
3085
Larry Hastings31826802013-10-19 00:09:25 -07003086 def directive_module(self, name):
3087 fields = name.split('.')
3088 new = fields.pop()
3089 module, cls = self.clinic._module_and_class(fields)
3090 if cls:
3091 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08003092
3093 if name in module.classes:
3094 fail("Already defined module " + repr(name) + "!")
3095
Larry Hastings31826802013-10-19 00:09:25 -07003096 m = Module(name, module)
3097 module.modules[name] = m
3098 self.block.signatures.append(m)
3099
Larry Hastingsc2047262014-01-25 20:43:29 -08003100 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07003101 fields = name.split('.')
3102 in_classes = False
3103 parent = self
3104 name = fields.pop()
3105 so_far = []
3106 module, cls = self.clinic._module_and_class(fields)
3107
Larry Hastingsc2047262014-01-25 20:43:29 -08003108 parent = cls or module
3109 if name in parent.classes:
3110 fail("Already defined class " + repr(name) + "!")
3111
3112 c = Class(name, module, cls, typedef, type_object)
3113 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07003114 self.block.signatures.append(c)
3115
Larry Hastingsbebf7352014-01-17 17:47:17 -08003116 def directive_set(self, name, value):
3117 if name not in ("line_prefix", "line_suffix"):
3118 fail("unknown variable", repr(name))
3119
3120 value = value.format_map({
3121 'block comment start': '/*',
3122 'block comment end': '*/',
3123 })
3124
3125 self.clinic.__dict__[name] = value
3126
3127 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003128 if command == 'new':
3129 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003130 return
3131
Zachary Ware071baa62014-01-21 23:07:12 -06003132 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003133 self.clinic.get_destination(name).clear()
3134 fail("unknown destination command", repr(command))
3135
3136
Larry Hastings0759f842015-04-03 13:09:02 -07003137 def directive_output(self, command_or_name, destination=''):
3138 fd = self.clinic.destination_buffers
Larry Hastingsbebf7352014-01-17 17:47:17 -08003139
Larry Hastings0759f842015-04-03 13:09:02 -07003140 if command_or_name == "preset":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003141 preset = self.clinic.presets.get(destination)
3142 if not preset:
3143 fail("Unknown preset " + repr(destination) + "!")
3144 fd.update(preset)
3145 return
3146
Larry Hastings0759f842015-04-03 13:09:02 -07003147 if command_or_name == "push":
3148 self.clinic.destination_buffers_stack.append(fd.copy())
Larry Hastingsbebf7352014-01-17 17:47:17 -08003149 return
3150
Larry Hastings0759f842015-04-03 13:09:02 -07003151 if command_or_name == "pop":
3152 if not self.clinic.destination_buffers_stack:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003153 fail("Can't 'output pop', stack is empty!")
Larry Hastings0759f842015-04-03 13:09:02 -07003154 previous_fd = self.clinic.destination_buffers_stack.pop()
Larry Hastingsbebf7352014-01-17 17:47:17 -08003155 fd.update(previous_fd)
3156 return
3157
3158 # secret command for debugging!
Larry Hastings0759f842015-04-03 13:09:02 -07003159 if command_or_name == "print":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003160 self.block.output.append(pprint.pformat(fd))
3161 self.block.output.append('\n')
3162 return
3163
3164 d = self.clinic.get_destination(destination)
3165
Larry Hastings0759f842015-04-03 13:09:02 -07003166 if command_or_name == "everything":
Larry Hastingsbebf7352014-01-17 17:47:17 -08003167 for name in list(fd):
3168 fd[name] = d
3169 return
3170
Larry Hastings0759f842015-04-03 13:09:02 -07003171 if command_or_name not in fd:
3172 fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd))
3173 fd[command_or_name] = d
Larry Hastingsbebf7352014-01-17 17:47:17 -08003174
3175 def directive_dump(self, name):
3176 self.block.output.append(self.clinic.get_destination(name).dump())
3177
3178 def directive_print(self, *args):
3179 self.block.output.append(' '.join(args))
3180 self.block.output.append('\n')
3181
3182 def directive_preserve(self):
3183 if self.preserve_output:
3184 fail("Can't have preserve twice in one block!")
3185 self.preserve_output = True
3186
Larry Hastings31826802013-10-19 00:09:25 -07003187 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003188 if self.kind is not CALLABLE:
3189 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003190 self.kind = CLASS_METHOD
3191
3192 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003193 if self.kind is not CALLABLE:
3194 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003195 self.kind = STATIC_METHOD
3196
3197 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003198 if self.coexist:
3199 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003200 self.coexist = True
3201
3202 def parse(self, block):
3203 self.reset()
3204 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003205 self.saved_output = self.block.output
3206 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003207 block_start = self.clinic.block_parser.line_number
3208 lines = block.input.split('\n')
3209 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3210 if '\t' in line:
3211 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3212 self.state(line)
3213
3214 self.next(self.state_terminal)
3215 self.state(None)
3216
Larry Hastingsbebf7352014-01-17 17:47:17 -08003217 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3218
3219 if self.preserve_output:
3220 if block.output:
3221 fail("'preserve' only works for blocks that don't produce any output!")
3222 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003223
3224 @staticmethod
3225 def ignore_line(line):
3226 # ignore comment-only lines
3227 if line.lstrip().startswith('#'):
3228 return True
3229
3230 # Ignore empty lines too
3231 # (but not in docstring sections!)
3232 if not line.strip():
3233 return True
3234
3235 return False
3236
3237 @staticmethod
3238 def calculate_indent(line):
3239 return len(line) - len(line.strip())
3240
3241 def next(self, state, line=None):
3242 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3243 self.state = state
3244 if line is not None:
3245 self.state(line)
3246
3247 def state_dsl_start(self, line):
3248 # self.block = self.ClinicOutputBlock(self)
3249 if self.ignore_line(line):
3250 return
Larry Hastings7726ac92014-01-31 22:03:12 -08003251
3252 # is it a directive?
3253 fields = shlex.split(line)
3254 directive_name = fields[0]
3255 directive = self.directives.get(directive_name, None)
3256 if directive:
3257 try:
3258 directive(*fields[1:])
3259 except TypeError as e:
3260 fail(str(e))
3261 return
3262
Larry Hastings31826802013-10-19 00:09:25 -07003263 self.next(self.state_modulename_name, line)
3264
3265 def state_modulename_name(self, line):
3266 # looking for declaration, which establishes the leftmost column
3267 # line should be
3268 # modulename.fnname [as c_basename] [-> return annotation]
3269 # square brackets denote optional syntax.
3270 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003271 # alternatively:
3272 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3273 # clones the parameters and return converter from that
3274 # function. you can't modify them. you must enter a
3275 # new docstring.
3276 #
Larry Hastings31826802013-10-19 00:09:25 -07003277 # (but we might find a directive first!)
3278 #
3279 # this line is permitted to start with whitespace.
3280 # we'll call this number of spaces F (for "function").
3281
3282 if not line.strip():
3283 return
3284
3285 self.indent.infer(line)
3286
Larry Hastings4a714d42014-01-14 22:22:41 -08003287 # are we cloning?
3288 before, equals, existing = line.rpartition('=')
3289 if equals:
3290 full_name, _, c_basename = before.partition(' as ')
3291 full_name = full_name.strip()
3292 c_basename = c_basename.strip()
3293 existing = existing.strip()
3294 if (is_legal_py_identifier(full_name) and
3295 (not c_basename or is_legal_c_identifier(c_basename)) and
3296 is_legal_py_identifier(existing)):
3297 # we're cloning!
3298 fields = [x.strip() for x in existing.split('.')]
3299 function_name = fields.pop()
3300 module, cls = self.clinic._module_and_class(fields)
3301
3302 for existing_function in (cls or module).functions:
3303 if existing_function.name == function_name:
3304 break
3305 else:
3306 existing_function = None
3307 if not existing_function:
Larry Hastings7726ac92014-01-31 22:03:12 -08003308 print("class", cls, "module", module, "existing", existing)
Larry Hastingsc2047262014-01-25 20:43:29 -08003309 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003310 fail("Couldn't find existing function " + repr(existing) + "!")
3311
3312 fields = [x.strip() for x in full_name.split('.')]
3313 function_name = fields.pop()
3314 module, cls = self.clinic._module_and_class(fields)
3315
3316 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3317 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
Larry Hastings7726ac92014-01-31 22:03:12 -08003318 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 -08003319
3320 self.block.signatures.append(self.function)
3321 (cls or module).functions.append(self.function)
3322 self.next(self.state_function_docstring)
3323 return
3324
Larry Hastings31826802013-10-19 00:09:25 -07003325 line, _, returns = line.partition('->')
3326
3327 full_name, _, c_basename = line.partition(' as ')
3328 full_name = full_name.strip()
3329 c_basename = c_basename.strip() or None
3330
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003331 if not is_legal_py_identifier(full_name):
3332 fail("Illegal function name: {}".format(full_name))
3333 if c_basename and not is_legal_c_identifier(c_basename):
3334 fail("Illegal C basename: {}".format(c_basename))
3335
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003336 return_converter = None
3337 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003338 ast_input = "def x() -> {}: pass".format(returns)
3339 module = None
3340 try:
3341 module = ast.parse(ast_input)
3342 except SyntaxError:
3343 pass
3344 if not module:
3345 fail("Badly-formed annotation for " + full_name + ": " + returns)
3346 try:
3347 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003348 if legacy:
3349 fail("Legacy converter {!r} not allowed as a return converter"
3350 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003351 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003352 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003353 return_converter = return_converters[name](**kwargs)
3354 except ValueError:
3355 fail("Badly-formed annotation for " + full_name + ": " + returns)
3356
3357 fields = [x.strip() for x in full_name.split('.')]
3358 function_name = fields.pop()
3359 module, cls = self.clinic._module_and_class(fields)
3360
Larry Hastings8666e652014-01-12 14:12:59 -08003361 fields = full_name.split('.')
3362 if fields[-1] == '__new__':
3363 if (self.kind != CLASS_METHOD) or (not cls):
3364 fail("__new__ must be a class method!")
3365 self.kind = METHOD_NEW
3366 elif fields[-1] == '__init__':
3367 if (self.kind != CALLABLE) or (not cls):
3368 fail("__init__ must be a normal method, not a class or static method!")
3369 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003370 if not return_converter:
3371 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003372 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003373 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003374
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003375 if not return_converter:
3376 return_converter = CReturnConverter()
3377
Larry Hastings31826802013-10-19 00:09:25 -07003378 if not module:
3379 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3380 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3381 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3382 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003383
3384 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003385 type, name = correct_name_for_self(self.function)
3386 kwargs = {}
3387 if cls and type == "PyObject *":
3388 kwargs['type'] = cls.typedef
Larry Hastings7726ac92014-01-31 22:03:12 -08003389 sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003390 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3391 self.function.parameters[sc.name] = p_self
3392
Larry Hastings4a714d42014-01-14 22:22:41 -08003393 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003394 self.next(self.state_parameters_start)
3395
3396 # Now entering the parameters section. The rules, formally stated:
3397 #
3398 # * All lines must be indented with spaces only.
3399 # * The first line must be a parameter declaration.
3400 # * The first line must be indented.
3401 # * This first line establishes the indent for parameters.
3402 # * We'll call this number of spaces P (for "parameter").
3403 # * Thenceforth:
3404 # * Lines indented with P spaces specify a parameter.
3405 # * Lines indented with > P spaces are docstrings for the previous
3406 # parameter.
3407 # * We'll call this number of spaces D (for "docstring").
3408 # * All subsequent lines indented with >= D spaces are stored as
3409 # part of the per-parameter docstring.
3410 # * All lines will have the first D spaces of the indent stripped
3411 # before they are stored.
3412 # * It's illegal to have a line starting with a number of spaces X
3413 # such that P < X < D.
3414 # * A line with < P spaces is the first line of the function
3415 # docstring, which ends processing for parameters and per-parameter
3416 # docstrings.
3417 # * The first line of the function docstring must be at the same
3418 # indent as the function declaration.
3419 # * It's illegal to have any line in the parameters section starting
3420 # with X spaces such that F < X < P. (As before, F is the indent
3421 # of the function declaration.)
3422 #
Larry Hastings31826802013-10-19 00:09:25 -07003423 # Also, currently Argument Clinic places the following restrictions on groups:
3424 # * Each group must contain at least one parameter.
3425 # * Each group may contain at most one group, which must be the furthest
3426 # thing in the group from the required parameters. (The nested group
3427 # must be the first in the group when it's before the required
3428 # parameters, and the last thing in the group when after the required
3429 # parameters.)
3430 # * There may be at most one (top-level) group to the left or right of
3431 # the required parameters.
3432 # * You must specify a slash, and it must be after all parameters.
3433 # (In other words: either all parameters are positional-only,
3434 # or none are.)
3435 #
3436 # Said another way:
3437 # * Each group must contain at least one parameter.
3438 # * All left square brackets before the required parameters must be
3439 # consecutive. (You can't have a left square bracket followed
3440 # by a parameter, then another left square bracket. You can't
3441 # have a left square bracket, a parameter, a right square bracket,
3442 # and then a left square bracket.)
3443 # * All right square brackets after the required parameters must be
3444 # consecutive.
3445 #
3446 # These rules are enforced with a single state variable:
3447 # "parameter_state". (Previously the code was a miasma of ifs and
3448 # separate boolean state variables.) The states are:
3449 #
Larry Hastingsc2047262014-01-25 20:43:29 -08003450 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] / <- line
3451 # 01 2 3 4 5 6 7 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003452 #
3453 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3454 # 1: ps_left_square_before. left square brackets before required parameters.
3455 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003456 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3457 # (we don't know yet). (renumber left groups!)
3458 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3459 # now must have default values.
3460 # 5: ps_group_after. in a group, after required parameters.
3461 # 6: ps_right_square_after. right square brackets after required parameters.
3462 # 7: ps_seen_slash. seen slash.
Larry Hastings31826802013-10-19 00:09:25 -07003463 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Larry Hastingsc2047262014-01-25 20:43:29 -08003464 ps_optional, ps_group_after, ps_right_square_after, ps_seen_slash = range(8)
Larry Hastings31826802013-10-19 00:09:25 -07003465
3466 def state_parameters_start(self, line):
3467 if self.ignore_line(line):
3468 return
3469
3470 # if this line is not indented, we have no parameters
3471 if not self.indent.infer(line):
3472 return self.next(self.state_function_docstring, line)
3473
Larry Hastings2a727912014-01-16 11:32:01 -08003474 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003475 return self.next(self.state_parameter, line)
3476
3477
3478 def to_required(self):
3479 """
3480 Transition to the "required" parameter state.
3481 """
3482 if self.parameter_state != self.ps_required:
3483 self.parameter_state = self.ps_required
3484 for p in self.function.parameters.values():
3485 p.group = -p.group
3486
3487 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003488 if self.parameter_continuation:
3489 line = self.parameter_continuation + ' ' + line.lstrip()
3490 self.parameter_continuation = ''
3491
Larry Hastings31826802013-10-19 00:09:25 -07003492 if self.ignore_line(line):
3493 return
3494
3495 assert self.indent.depth == 2
3496 indent = self.indent.infer(line)
3497 if indent == -1:
3498 # we outdented, must be to definition column
3499 return self.next(self.state_function_docstring, line)
3500
3501 if indent == 1:
3502 # we indented, must be to new parameter docstring column
3503 return self.next(self.state_parameter_docstring_start, line)
3504
Larry Hastings2a727912014-01-16 11:32:01 -08003505 line = line.rstrip()
3506 if line.endswith('\\'):
3507 self.parameter_continuation = line[:-1]
3508 return
3509
Larry Hastings31826802013-10-19 00:09:25 -07003510 line = line.lstrip()
3511
3512 if line in ('*', '/', '[', ']'):
3513 self.parse_special_symbol(line)
3514 return
3515
3516 if self.parameter_state in (self.ps_start, self.ps_required):
3517 self.to_required()
3518 elif self.parameter_state == self.ps_left_square_before:
3519 self.parameter_state = self.ps_group_before
3520 elif self.parameter_state == self.ps_group_before:
3521 if not self.group:
3522 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003523 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003524 pass
3525 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003526 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003527
Larry Hastings7726ac92014-01-31 22:03:12 -08003528 # handle "as" for parameters too
3529 c_name = None
3530 name, have_as_token, trailing = line.partition(' as ')
3531 if have_as_token:
3532 name = name.strip()
3533 if ' ' not in name:
3534 fields = trailing.strip().split(' ')
3535 if not fields:
3536 fail("Invalid 'as' clause!")
3537 c_name = fields[0]
3538 if c_name.endswith(':'):
3539 name += ':'
3540 c_name = c_name[:-1]
3541 fields[0] = name
3542 line = ' '.join(fields)
3543
Larry Hastings2a727912014-01-16 11:32:01 -08003544 base, equals, default = line.rpartition('=')
3545 if not equals:
3546 base = default
3547 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003548
Larry Hastings31826802013-10-19 00:09:25 -07003549 module = None
3550 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003551 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003552 module = ast.parse(ast_input)
3553 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003554 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003555 # the last = was probably inside a function call, like
3556 # i: int(nullable=True)
3557 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003558 default = None
3559 ast_input = "def x({}): pass".format(line)
3560 module = ast.parse(ast_input)
3561 except SyntaxError:
3562 pass
Larry Hastings31826802013-10-19 00:09:25 -07003563 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003564 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003565
3566 function_args = module.body[0].args
3567 parameter = function_args.args[0]
3568
Larry Hastings16c51912014-01-07 11:53:01 -08003569 parameter_name = parameter.arg
3570 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3571
Larry Hastings2a727912014-01-16 11:32:01 -08003572 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003573 if self.parameter_state == self.ps_optional:
3574 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 -08003575 value = unspecified
3576 if 'py_default' in kwargs:
3577 fail("You can't specify py_default without specifying a default value!")
3578 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003579 if self.parameter_state == self.ps_required:
3580 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003581 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003582 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003583 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003584 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003585 try:
3586 module = ast.parse(ast_input)
3587
Larry Hastings5c661892014-01-24 06:17:25 -08003588 if 'c_default' not in kwargs:
3589 # we can only represent very simple data values in C.
3590 # detect whether default is okay, via a blacklist
3591 # of disallowed ast nodes.
3592 class DetectBadNodes(ast.NodeVisitor):
3593 bad = False
3594 def bad_node(self, node):
3595 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003596
Larry Hastings5c661892014-01-24 06:17:25 -08003597 # inline function call
3598 visit_Call = bad_node
3599 # inline if statement ("x = 3 if y else z")
3600 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003601
Larry Hastings5c661892014-01-24 06:17:25 -08003602 # comprehensions and generator expressions
3603 visit_ListComp = visit_SetComp = bad_node
3604 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003605
Larry Hastings5c661892014-01-24 06:17:25 -08003606 # literals for advanced types
3607 visit_Dict = visit_Set = bad_node
3608 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003609
Larry Hastings5c661892014-01-24 06:17:25 -08003610 # "starred": "a = [1, 2, 3]; *a"
3611 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003612
Larry Hastings5c661892014-01-24 06:17:25 -08003613 # allow ellipsis, for now
3614 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003615
Larry Hastings5c661892014-01-24 06:17:25 -08003616 blacklist = DetectBadNodes()
3617 blacklist.visit(module)
3618 bad = blacklist.bad
3619 else:
3620 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003621 # but at least make an attempt at ensuring it's a valid expression.
3622 try:
3623 value = eval(default)
3624 if value == unspecified:
3625 fail("'unspecified' is not a legal default value!")
3626 except NameError:
3627 pass # probably a named constant
3628 except Exception as e:
3629 fail("Malformed expression given as default value\n"
3630 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003631 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003632 fail("Unsupported expression as default value: " + repr(default))
3633
3634 expr = module.body[0].value
3635 # mild hack: explicitly support NULL as a default value
3636 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3637 value = NULL
3638 py_default = 'None'
3639 c_default = "NULL"
3640 elif (isinstance(expr, ast.BinOp) or
3641 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3642 c_default = kwargs.get("c_default")
3643 if not (isinstance(c_default, str) and c_default):
3644 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3645 py_default = default
3646 value = unknown
3647 elif isinstance(expr, ast.Attribute):
3648 a = []
3649 n = expr
3650 while isinstance(n, ast.Attribute):
3651 a.append(n.attr)
3652 n = n.value
3653 if not isinstance(n, ast.Name):
3654 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3655 a.append(n.id)
3656 py_default = ".".join(reversed(a))
3657
3658 c_default = kwargs.get("c_default")
3659 if not (isinstance(c_default, str) and c_default):
3660 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3661
3662 try:
3663 value = eval(py_default)
3664 except NameError:
3665 value = unknown
3666 else:
3667 value = ast.literal_eval(expr)
3668 py_default = repr(value)
3669 if isinstance(value, (bool, None.__class__)):
3670 c_default = "Py_" + py_default
3671 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003672 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003673 else:
3674 c_default = py_default
3675
3676 except SyntaxError as e:
3677 fail("Syntax error: " + repr(e.text))
3678 except (ValueError, AttributeError):
3679 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003680 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003681 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003682 if not (isinstance(c_default, str) and c_default):
3683 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3684
Larry Hastings2a727912014-01-16 11:32:01 -08003685 kwargs.setdefault('c_default', c_default)
3686 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003687
Larry Hastings31826802013-10-19 00:09:25 -07003688 dict = legacy_converters if legacy else converters
3689 legacy_str = "legacy " if legacy else ""
3690 if name not in dict:
3691 fail('{} is not a valid {}converter'.format(name, legacy_str))
Larry Hastings7726ac92014-01-31 22:03:12 -08003692 # if you use a c_name for the parameter, we just give that name to the converter
3693 # but the parameter object gets the python name
3694 converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs)
Larry Hastings31826802013-10-19 00:09:25 -07003695
3696 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003697
3698 if isinstance(converter, self_converter):
3699 if len(self.function.parameters) == 1:
3700 if (self.parameter_state != self.ps_required):
3701 fail("A 'self' parameter cannot be marked optional.")
3702 if value is not unspecified:
3703 fail("A 'self' parameter cannot have a default value.")
3704 if self.group:
3705 fail("A 'self' parameter cannot be in an optional group.")
3706 kind = inspect.Parameter.POSITIONAL_ONLY
3707 self.parameter_state = self.ps_start
3708 self.function.parameters.clear()
3709 else:
3710 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3711
Larry Hastings31826802013-10-19 00:09:25 -07003712 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003713
3714 if parameter_name in self.function.parameters:
3715 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003716 self.function.parameters[parameter_name] = p
3717
3718 def parse_converter(self, annotation):
3719 if isinstance(annotation, ast.Str):
3720 return annotation.s, True, {}
3721
3722 if isinstance(annotation, ast.Name):
3723 return annotation.id, False, {}
3724
Larry Hastings4a55fc52014-01-12 11:09:57 -08003725 if not isinstance(annotation, ast.Call):
3726 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003727
3728 name = annotation.func.id
3729 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
3730 return name, False, kwargs
3731
3732 def parse_special_symbol(self, symbol):
3733 if self.parameter_state == self.ps_seen_slash:
3734 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
3735
3736 if symbol == '*':
3737 if self.keyword_only:
3738 fail("Function " + self.function.name + " uses '*' more than once.")
3739 self.keyword_only = True
3740 elif symbol == '[':
3741 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3742 self.parameter_state = self.ps_left_square_before
3743 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3744 self.parameter_state = self.ps_group_after
3745 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003746 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003747 self.group += 1
Larry Hastings2623c8c2014-02-08 22:15:29 -08003748 self.function.docstring_only = True
Larry Hastings31826802013-10-19 00:09:25 -07003749 elif symbol == ']':
3750 if not self.group:
3751 fail("Function " + self.function.name + " has a ] without a matching [.")
3752 if not any(p.group == self.group for p in self.function.parameters.values()):
3753 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3754 self.group -= 1
3755 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3756 self.parameter_state = self.ps_group_before
3757 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3758 self.parameter_state = self.ps_right_square_after
3759 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003760 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003761 elif symbol == '/':
Larry Hastingsc2047262014-01-25 20:43:29 -08003762 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003763 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003764 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3765 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003766 if self.keyword_only:
3767 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3768 self.parameter_state = self.ps_seen_slash
Berker Peksagf23530f2014-10-19 18:04:38 +03003769 # fixup preceding parameters
Larry Hastings31826802013-10-19 00:09:25 -07003770 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08003771 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07003772 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3773 p.kind = inspect.Parameter.POSITIONAL_ONLY
3774
3775 def state_parameter_docstring_start(self, line):
3776 self.parameter_docstring_indent = len(self.indent.margin)
3777 assert self.indent.depth == 3
3778 return self.next(self.state_parameter_docstring, line)
3779
3780 # every line of the docstring must start with at least F spaces,
3781 # where F > P.
3782 # these F spaces will be stripped.
3783 def state_parameter_docstring(self, line):
3784 stripped = line.strip()
3785 if stripped.startswith('#'):
3786 return
3787
3788 indent = self.indent.measure(line)
3789 if indent < self.parameter_docstring_indent:
3790 self.indent.infer(line)
3791 assert self.indent.depth < 3
3792 if self.indent.depth == 2:
3793 # back to a parameter
3794 return self.next(self.state_parameter, line)
3795 assert self.indent.depth == 1
3796 return self.next(self.state_function_docstring, line)
3797
3798 assert self.function.parameters
3799 last_parameter = next(reversed(list(self.function.parameters.values())))
3800
3801 new_docstring = last_parameter.docstring
3802
3803 if new_docstring:
3804 new_docstring += '\n'
3805 if stripped:
3806 new_docstring += self.indent.dedent(line)
3807
3808 last_parameter.docstring = new_docstring
3809
3810 # the final stanza of the DSL is the docstring.
3811 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003812 if self.group:
3813 fail("Function " + self.function.name + " has a ] without a matching [.")
3814
3815 stripped = line.strip()
3816 if stripped.startswith('#'):
3817 return
3818
3819 new_docstring = self.function.docstring
3820 if new_docstring:
3821 new_docstring += "\n"
3822 if stripped:
3823 line = self.indent.dedent(line).rstrip()
3824 else:
3825 line = ''
3826 new_docstring += line
3827 self.function.docstring = new_docstring
3828
3829 def format_docstring(self):
3830 f = self.function
3831
Larry Hastings5c661892014-01-24 06:17:25 -08003832 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
3833 if new_or_init and not f.docstring:
3834 # don't render a docstring at all, no signature, nothing.
3835 return f.docstring
3836
Larry Hastings2623c8c2014-02-08 22:15:29 -08003837 text, add, output = _text_accumulator()
Larry Hastings7726ac92014-01-31 22:03:12 -08003838 parameters = f.render_parameters
Larry Hastings31826802013-10-19 00:09:25 -07003839
3840 ##
3841 ## docstring first line
3842 ##
3843
Larry Hastings2623c8c2014-02-08 22:15:29 -08003844 if new_or_init:
3845 # classes get *just* the name of the class
3846 # not __new__, not __init__, and not module.classname
3847 assert f.cls
3848 add(f.cls.name)
Larry Hastings46258262014-01-22 03:05:49 -08003849 else:
Larry Hastings2623c8c2014-02-08 22:15:29 -08003850 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07003851 add('(')
3852
3853 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08003854 assert parameters, "We should always have a self parameter. " + repr(f)
3855 assert isinstance(parameters[0].converter, self_converter)
3856 parameters[0].right_bracket_count = 0
3857 parameters_after_self = parameters[1:]
3858 if parameters_after_self:
Larry Hastings31826802013-10-19 00:09:25 -07003859 # for now, the only way Clinic supports positional-only parameters
Larry Hastings5c661892014-01-24 06:17:25 -08003860 # is if all of them are positional-only...
3861 #
3862 # ... except for self! self is always positional-only.
3863
3864 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters_after_self]
3865 if parameters_after_self[0].kind == inspect.Parameter.POSITIONAL_ONLY:
Larry Hastings31826802013-10-19 00:09:25 -07003866 assert all(positional_only_parameters)
3867 for p in parameters:
3868 p.right_bracket_count = abs(p.group)
3869 else:
3870 # don't put any right brackets around non-positional-only parameters, ever.
Larry Hastings5c661892014-01-24 06:17:25 -08003871 for p in parameters_after_self:
Larry Hastings31826802013-10-19 00:09:25 -07003872 p.right_bracket_count = 0
3873
3874 right_bracket_count = 0
3875
3876 def fix_right_bracket_count(desired):
3877 nonlocal right_bracket_count
3878 s = ''
3879 while right_bracket_count < desired:
3880 s += '['
3881 right_bracket_count += 1
3882 while right_bracket_count > desired:
3883 s += ']'
3884 right_bracket_count -= 1
3885 return s
3886
Larry Hastings2623c8c2014-02-08 22:15:29 -08003887 need_slash = False
3888 added_slash = False
3889 need_a_trailing_slash = False
3890
3891 # we only need a trailing slash:
3892 # * if this is not a "docstring_only" signature
3893 # * and if the last *shown* parameter is
3894 # positional only
3895 if not f.docstring_only:
3896 for p in reversed(parameters):
3897 if not p.converter.show_in_signature:
3898 continue
3899 if p.is_positional_only():
3900 need_a_trailing_slash = True
3901 break
3902
3903
Larry Hastings31826802013-10-19 00:09:25 -07003904 added_star = False
Larry Hastings2623c8c2014-02-08 22:15:29 -08003905
3906 first_parameter = True
3907 last_p = parameters[-1]
3908 line_length = len(''.join(text))
3909 indent = " " * line_length
3910 def add_parameter(text):
3911 nonlocal line_length
3912 nonlocal first_parameter
3913 if first_parameter:
3914 s = text
3915 first_parameter = False
3916 else:
3917 s = ' ' + text
3918 if line_length + len(s) >= 72:
3919 add('\n')
3920 add(indent)
3921 line_length = len(indent)
3922 s = text
3923 line_length += len(s)
3924 add(s)
Larry Hastings31826802013-10-19 00:09:25 -07003925
3926 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08003927 if not p.converter.show_in_signature:
3928 continue
Larry Hastings31826802013-10-19 00:09:25 -07003929 assert p.name
3930
Larry Hastings2623c8c2014-02-08 22:15:29 -08003931 is_self = isinstance(p.converter, self_converter)
3932 if is_self and f.docstring_only:
3933 # this isn't a real machine-parsable signature,
3934 # so let's not print the "self" parameter
3935 continue
3936
3937 if p.is_positional_only():
3938 need_slash = not f.docstring_only
3939 elif need_slash and not (added_slash or p.is_positional_only()):
3940 added_slash = True
3941 add_parameter('/,')
3942
Larry Hastings31826802013-10-19 00:09:25 -07003943 if p.is_keyword_only() and not added_star:
3944 added_star = True
Larry Hastings2623c8c2014-02-08 22:15:29 -08003945 add_parameter('*,')
3946
3947 p_add, p_output = text_accumulator()
3948 p_add(fix_right_bracket_count(p.right_bracket_count))
3949
3950 if isinstance(p.converter, self_converter):
3951 # annotate first parameter as being a "self".
3952 #
3953 # if inspect.Signature gets this function,
3954 # and it's already bound, the self parameter
3955 # will be stripped off.
3956 #
3957 # if it's not bound, it should be marked
3958 # as positional-only.
3959 #
3960 # note: we don't print "self" for __init__,
3961 # because this isn't actually the signature
3962 # for __init__. (it can't be, __init__ doesn't
3963 # have a docstring.) if this is an __init__
3964 # (or __new__), then this signature is for
Berker Peksagf23530f2014-10-19 18:04:38 +03003965 # calling the class to construct a new instance.
Larry Hastings2623c8c2014-02-08 22:15:29 -08003966 p_add('$')
Larry Hastings31826802013-10-19 00:09:25 -07003967
Larry Hastings5c661892014-01-24 06:17:25 -08003968 name = p.converter.signature_name or p.name
Larry Hastings2623c8c2014-02-08 22:15:29 -08003969 p_add(name)
Larry Hastings581ee362014-01-28 05:00:08 -08003970
Larry Hastings31826802013-10-19 00:09:25 -07003971 if p.converter.is_optional():
Larry Hastings2623c8c2014-02-08 22:15:29 -08003972 p_add('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08003973 value = p.converter.py_default
3974 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08003975 value = repr(p.converter.default)
Larry Hastings2623c8c2014-02-08 22:15:29 -08003976 p_add(value)
3977
3978 if (p != last_p) or need_a_trailing_slash:
3979 p_add(',')
3980
3981 add_parameter(p_output())
Larry Hastings31826802013-10-19 00:09:25 -07003982
3983 add(fix_right_bracket_count(0))
Larry Hastings2623c8c2014-02-08 22:15:29 -08003984 if need_a_trailing_slash:
3985 add_parameter('/')
Larry Hastings31826802013-10-19 00:09:25 -07003986 add(')')
3987
Larry Hastings2a727912014-01-16 11:32:01 -08003988 # PEP 8 says:
3989 #
3990 # The Python standard library will not use function annotations
3991 # as that would result in a premature commitment to a particular
3992 # annotation style. Instead, the annotations are left for users
3993 # to discover and experiment with useful annotation styles.
3994 #
3995 # therefore this is commented out:
3996 #
3997 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003998 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08003999 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07004000
Larry Hastings2623c8c2014-02-08 22:15:29 -08004001 if not f.docstring_only:
4002 add("\n--\n")
4003
Larry Hastings31826802013-10-19 00:09:25 -07004004 docstring_first_line = output()
4005
4006 # now fix up the places where the brackets look wrong
4007 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
4008
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004009 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07004010 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004011 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07004012 for p in parameters:
4013 if not p.docstring.strip():
4014 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004015 if spacer_line:
4016 add('\n')
4017 else:
4018 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07004019 add(" ")
4020 add(p.name)
4021 add('\n')
4022 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004023 parameters = output()
4024 if parameters:
4025 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07004026
4027 ##
4028 ## docstring body
4029 ##
4030
4031 docstring = f.docstring.rstrip()
4032 lines = [line.rstrip() for line in docstring.split('\n')]
4033
4034 # Enforce the summary line!
4035 # The first line of a docstring should be a summary of the function.
4036 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
4037 # by itself.
4038 #
4039 # Argument Clinic enforces the following rule:
4040 # * either the docstring is empty,
4041 # * or it must have a summary line.
4042 #
4043 # Guido said Clinic should enforce this:
4044 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
4045
4046 if len(lines) >= 2:
4047 if lines[1]:
4048 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
4049 "Every non-blank function docstring must start with\n" +
4050 "a single line summary followed by an empty line.")
4051 elif len(lines) == 1:
4052 # the docstring is only one line right now--the summary line.
4053 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004054 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07004055 lines.append('')
4056
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004057 parameters_marker_count = len(docstring.split('{parameters}')) - 1
4058 if parameters_marker_count > 1:
4059 fail('You may not specify {parameters} more than once in a docstring!')
4060
4061 if not parameters_marker_count:
4062 # insert after summary line
4063 lines.insert(2, '{parameters}')
4064
4065 # insert at front of docstring
4066 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07004067
4068 docstring = "\n".join(lines)
4069
4070 add(docstring)
4071 docstring = output()
4072
Larry Hastings44e2eaa2013-11-23 15:37:55 -08004073 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07004074 docstring = docstring.rstrip()
4075
4076 return docstring
4077
4078 def state_terminal(self, line):
4079 """
4080 Called when processing the block is done.
4081 """
4082 assert not line
4083
4084 if not self.function:
4085 return
4086
4087 if self.keyword_only:
4088 values = self.function.parameters.values()
4089 if not values:
4090 no_parameter_after_star = True
4091 else:
4092 last_parameter = next(reversed(list(values)))
4093 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
4094 if no_parameter_after_star:
4095 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
4096
4097 # remove trailing whitespace from all parameter docstrings
4098 for name, value in self.function.parameters.items():
4099 if not value:
4100 continue
4101 value.docstring = value.docstring.rstrip()
4102
4103 self.function.docstring = self.format_docstring()
4104
4105
Larry Hastings5c661892014-01-24 06:17:25 -08004106
4107
Larry Hastings31826802013-10-19 00:09:25 -07004108# maps strings to callables.
4109# the callable should return an object
4110# that implements the clinic parser
4111# interface (__init__ and parse).
4112#
4113# example parsers:
4114# "clinic", handles the Clinic DSL
4115# "python", handles running Python code
4116#
4117parsers = {'clinic' : DSLParser, 'python': PythonParser}
4118
4119
4120clinic = None
4121
4122
4123def main(argv):
4124 import sys
4125
4126 if sys.version_info.major < 3 or sys.version_info.minor < 3:
4127 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
4128
4129 import argparse
4130 cmdline = argparse.ArgumentParser()
4131 cmdline.add_argument("-f", "--force", action='store_true')
4132 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08004133 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004134 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004135 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07004136 cmdline.add_argument("filename", type=str, nargs="*")
4137 ns = cmdline.parse_args(argv)
4138
4139 if ns.converters:
4140 if ns.filename:
4141 print("Usage error: can't specify --converters and a filename at the same time.")
4142 print()
4143 cmdline.print_usage()
4144 sys.exit(-1)
4145 converters = []
4146 return_converters = []
4147 ignored = set("""
4148 add_c_converter
4149 add_c_return_converter
4150 add_default_legacy_c_converter
4151 add_legacy_c_converter
4152 """.strip().split())
4153 module = globals()
4154 for name in module:
4155 for suffix, ids in (
4156 ("_return_converter", return_converters),
4157 ("_converter", converters),
4158 ):
4159 if name in ignored:
4160 continue
4161 if name.endswith(suffix):
4162 ids.append((name, name[:-len(suffix)]))
4163 break
4164 print()
4165
4166 print("Legacy converters:")
4167 legacy = sorted(legacy_converters)
4168 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
4169 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
4170 print()
4171
4172 for title, attribute, ids in (
4173 ("Converters", 'converter_init', converters),
4174 ("Return converters", 'return_converter_init', return_converters),
4175 ):
4176 print(title + ":")
4177 longest = -1
4178 for name, short_name in ids:
4179 longest = max(longest, len(short_name))
4180 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
4181 cls = module[name]
4182 callable = getattr(cls, attribute, None)
4183 if not callable:
4184 continue
4185 signature = inspect.signature(callable)
4186 parameters = []
4187 for parameter_name, parameter in signature.parameters.items():
4188 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
4189 if parameter.default != inspect.Parameter.empty:
4190 s = '{}={!r}'.format(parameter_name, parameter.default)
4191 else:
4192 s = parameter_name
4193 parameters.append(s)
4194 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004195 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004196 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4197 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004198 sys.exit(0)
4199
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004200 if ns.make:
4201 if ns.output or ns.filename:
4202 print("Usage error: can't use -o or filenames with --make.")
4203 print()
4204 cmdline.print_usage()
4205 sys.exit(-1)
4206 for root, dirs, files in os.walk('.'):
Larry Hastings5c661892014-01-24 06:17:25 -08004207 for rcs_dir in ('.svn', '.git', '.hg', 'build'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004208 if rcs_dir in dirs:
4209 dirs.remove(rcs_dir)
4210 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004211 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004212 continue
4213 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004214 if ns.verbose:
4215 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004216 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004217 return
4218
Larry Hastings31826802013-10-19 00:09:25 -07004219 if not ns.filename:
4220 cmdline.print_usage()
4221 sys.exit(-1)
4222
4223 if ns.output and len(ns.filename) > 1:
4224 print("Usage error: can't use -o with multiple filenames.")
4225 print()
4226 cmdline.print_usage()
4227 sys.exit(-1)
4228
4229 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004230 if ns.verbose:
4231 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004232 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004233
4234
4235if __name__ == "__main__":
4236 sys.exit(main(sys.argv[1:]))