blob: 4d58056b8a19d6d20b1bd4abc88140e571c319aa [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
13import functools
14import hashlib
15import inspect
16import io
17import itertools
18import os
Larry Hastingsbebf7352014-01-17 17:47:17 -080019import pprint
Larry Hastings31826802013-10-19 00:09:25 -070020import re
21import shlex
22import sys
23import tempfile
24import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010025import traceback
Larry Hastingsbebf7352014-01-17 17:47:17 -080026import uuid
Larry Hastings31826802013-10-19 00:09:25 -070027
Larry Hastings31826802013-10-19 00:09:25 -070028# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070029#
30# soon:
31#
32# * allow mixing any two of {positional-only, positional-or-keyword,
33# keyword-only}
34# * dict constructor uses positional-only and keyword-only
35# * max and min use positional only with an optional group
36# and keyword-only
37#
Larry Hastings31826802013-10-19 00:09:25 -070038
Larry Hastingsebdcb502013-11-23 14:54:00 -080039version = '1'
40
Larry Hastings31826802013-10-19 00:09:25 -070041_empty = inspect._empty
42_void = inspect._void
43
Larry Hastings4a55fc52014-01-12 11:09:57 -080044NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070045
46class Unspecified:
47 def __repr__(self):
48 return '<Unspecified>'
49
50unspecified = Unspecified()
51
52
53class Null:
54 def __repr__(self):
55 return '<Null>'
56
57NULL = Null()
58
59
Larry Hastings2a727912014-01-16 11:32:01 -080060class Unknown:
61 def __repr__(self):
62 return '<Unknown>'
63
64unknown = Unknown()
65
66
Larry Hastings31826802013-10-19 00:09:25 -070067def _text_accumulator():
68 text = []
69 def output():
70 s = ''.join(text)
71 text.clear()
72 return s
73 return text, text.append, output
74
75
76def text_accumulator():
77 """
78 Creates a simple text accumulator / joiner.
79
80 Returns a pair of callables:
81 append, output
82 "append" appends a string to the accumulator.
83 "output" returns the contents of the accumulator
84 joined together (''.join(accumulator)) and
85 empties the accumulator.
86 """
87 text, append, output = _text_accumulator()
88 return append, output
89
90
Larry Hastingsbebf7352014-01-17 17:47:17 -080091def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -070092 joined = " ".join([str(a) for a in args])
93 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -080094 if fail:
95 add("Error")
96 else:
97 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -070098 if clinic:
99 if filename is None:
100 filename = clinic.filename
101 if clinic.block_parser and (line_number is None):
102 line_number = clinic.block_parser.line_number
103 if filename is not None:
104 add(' in file "' + filename + '"')
105 if line_number is not None:
106 add(" on line " + str(line_number))
107 add(':\n')
108 add(joined)
109 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800110 if fail:
111 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700112
113
Larry Hastingsbebf7352014-01-17 17:47:17 -0800114def warn(*args, filename=None, line_number=None):
115 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
116
117def fail(*args, filename=None, line_number=None):
118 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
119
Larry Hastings31826802013-10-19 00:09:25 -0700120
121def quoted_for_c_string(s):
122 for old, new in (
123 ('"', '\\"'),
124 ("'", "\\'"),
125 ):
126 s = s.replace(old, new)
127 return s
128
Larry Hastings4903e002014-01-18 00:26:16 -0800129def c_repr(s):
130 return '"' + s + '"'
131
132
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700133is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
134
135def is_legal_py_identifier(s):
136 return all(is_legal_c_identifier(field) for field in s.split('.'))
137
Larry Hastingsbebf7352014-01-17 17:47:17 -0800138# identifiers that are okay in Python but aren't a good idea in C.
139# so if they're used Argument Clinic will add "_value" to the end
140# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700141c_keywords = set("""
Larry Hastingsbebf7352014-01-17 17:47:17 -0800142asm auto break case char cls const continue default do double
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800143else enum extern float for goto if inline int long module null
144register return self short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800145typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700146""".strip().split())
147
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700148def ensure_legal_c_identifier(s):
149 # for now, just complain if what we're given isn't legal
150 if not is_legal_c_identifier(s):
151 fail("Illegal C identifier: {}".format(s))
152 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700153 if s in c_keywords:
154 return s + "_value"
155 return s
156
157def rstrip_lines(s):
158 text, add, output = _text_accumulator()
159 for line in s.split('\n'):
160 add(line.rstrip())
161 add('\n')
162 text.pop()
163 return output()
164
165def linear_format(s, **kwargs):
166 """
167 Perform str.format-like substitution, except:
168 * The strings substituted must be on lines by
169 themselves. (This line is the "source line".)
170 * If the substitution text is empty, the source line
171 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800172 * If the field is not recognized, the original line
173 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700174 * If the substitution text is not empty:
175 * Each line of the substituted text is indented
176 by the indent of the source line.
177 * A newline will be added to the end.
178 """
179
180 add, output = text_accumulator()
181 for line in s.split('\n'):
182 indent, curly, trailing = line.partition('{')
183 if not curly:
184 add(line)
185 add('\n')
186 continue
187
188 name, curl, trailing = trailing.partition('}')
189 if not curly or name not in kwargs:
190 add(line)
191 add('\n')
192 continue
193
194 if trailing:
195 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
196 if indent.strip():
197 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
198
199 value = kwargs[name]
200 if not value:
201 continue
202
203 value = textwrap.indent(rstrip_lines(value), indent)
204 add(value)
205 add('\n')
206
207 return output()[:-1]
208
Larry Hastingsbebf7352014-01-17 17:47:17 -0800209def indent_all_lines(s, prefix):
210 """
211 Returns 's', with 'prefix' prepended to all lines.
212
213 If the last line is empty, prefix is not prepended
214 to it. (If s is blank, returns s unchanged.)
215
216 (textwrap.indent only adds to non-blank lines.)
217 """
218 split = s.split('\n')
219 last = split.pop()
220 final = []
221 for line in split:
222 final.append(prefix)
223 final.append(line)
224 final.append('\n')
225 if last:
226 final.append(prefix)
227 final.append(last)
228 return ''.join(final)
229
230def suffix_all_lines(s, suffix):
231 """
232 Returns 's', with 'suffix' appended to all lines.
233
234 If the last line is empty, suffix is not appended
235 to it. (If s is blank, returns s unchanged.)
236 """
237 split = s.split('\n')
238 last = split.pop()
239 final = []
240 for line in split:
241 final.append(line)
242 final.append(suffix)
243 final.append('\n')
244 if last:
245 final.append(last)
246 final.append(suffix)
247 return ''.join(final)
248
249
Larry Hastingsebdcb502013-11-23 14:54:00 -0800250def version_splitter(s):
251 """Splits a version string into a tuple of integers.
252
253 The following ASCII characters are allowed, and employ
254 the following conversions:
255 a -> -3
256 b -> -2
257 c -> -1
258 (This permits Python-style version strings such as "1.4b3".)
259 """
260 version = []
261 accumulator = []
262 def flush():
263 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800264 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800265 version.append(int(''.join(accumulator)))
266 accumulator.clear()
267
268 for c in s:
269 if c.isdigit():
270 accumulator.append(c)
271 elif c == '.':
272 flush()
273 elif c in 'abc':
274 flush()
275 version.append('abc'.index(c) - 3)
276 else:
277 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
278 flush()
279 return tuple(version)
280
281def version_comparitor(version1, version2):
282 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
283 for i, (a, b) in enumerate(iterator):
284 if a < b:
285 return -1
286 if a > b:
287 return 1
288 return 0
289
Larry Hastings31826802013-10-19 00:09:25 -0700290
291class CRenderData:
292 def __init__(self):
293
294 # The C statements to declare variables.
295 # Should be full lines with \n eol characters.
296 self.declarations = []
297
298 # The C statements required to initialize the variables before the parse call.
299 # Should be full lines with \n eol characters.
300 self.initializers = []
301
302 # The entries for the "keywords" array for PyArg_ParseTuple.
303 # Should be individual strings representing the names.
304 self.keywords = []
305
306 # The "format units" for PyArg_ParseTuple.
307 # Should be individual strings that will get
308 self.format_units = []
309
310 # The varargs arguments for PyArg_ParseTuple.
311 self.parse_arguments = []
312
313 # The parameter declarations for the impl function.
314 self.impl_parameters = []
315
316 # The arguments to the impl function at the time it's called.
317 self.impl_arguments = []
318
319 # For return converters: the name of the variable that
320 # should receive the value returned by the impl.
321 self.return_value = "return_value"
322
323 # For return converters: the code to convert the return
324 # value from the parse function. This is also where
325 # you should check the _return_value for errors, and
326 # "goto exit" if there are any.
327 self.return_conversion = []
328
329 # The C statements required to clean up after the impl call.
330 self.cleanup = []
331
332
333class Language(metaclass=abc.ABCMeta):
334
335 start_line = ""
336 body_prefix = ""
337 stop_line = ""
338 checksum_line = ""
339
340 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800341 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700342 pass
343
344 def validate(self):
345 def assert_only_one(field, token='dsl_name'):
346 line = getattr(self, field)
347 token = '{' + token + '}'
348 if len(line.split(token)) != 2:
349 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
350 assert_only_one('start_line')
351 assert_only_one('stop_line')
352 assert_only_one('checksum_line')
353 assert_only_one('checksum_line', 'checksum')
354
355 if len(self.body_prefix.split('{dsl_name}')) >= 3:
356 fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
357
358
359
360class PythonLanguage(Language):
361
362 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800363 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700364 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800365 stop_line = "#[{dsl_name} start generated code]*/"
366 checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700367
368
369def permute_left_option_groups(l):
370 """
371 Given [1, 2, 3], should yield:
372 ()
373 (3,)
374 (2, 3)
375 (1, 2, 3)
376 """
377 yield tuple()
378 accumulator = []
379 for group in reversed(l):
380 accumulator = list(group) + accumulator
381 yield tuple(accumulator)
382
383
384def permute_right_option_groups(l):
385 """
386 Given [1, 2, 3], should yield:
387 ()
388 (1,)
389 (1, 2)
390 (1, 2, 3)
391 """
392 yield tuple()
393 accumulator = []
394 for group in l:
395 accumulator.extend(group)
396 yield tuple(accumulator)
397
398
399def permute_optional_groups(left, required, right):
400 """
401 Generator function that computes the set of acceptable
402 argument lists for the provided iterables of
403 argument groups. (Actually it generates a tuple of tuples.)
404
405 Algorithm: prefer left options over right options.
406
407 If required is empty, left must also be empty.
408 """
409 required = tuple(required)
410 result = []
411
412 if not required:
413 assert not left
414
415 accumulator = []
416 counts = set()
417 for r in permute_right_option_groups(right):
418 for l in permute_left_option_groups(left):
419 t = l + required + r
420 if len(t) in counts:
421 continue
422 counts.add(len(t))
423 accumulator.append(t)
424
425 accumulator.sort(key=len)
426 return tuple(accumulator)
427
428
429class CLanguage(Language):
430
Larry Hastings61272b72014-01-07 12:41:53 -0800431 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700432 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800433 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700434 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800435 stop_line = "[{dsl_name} start generated code]*/"
436 checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700437
Larry Hastingsbebf7352014-01-17 17:47:17 -0800438 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700439 function = None
440 for o in signatures:
441 if isinstance(o, Function):
442 if function:
443 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
444 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800445 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700446
447 def docstring_for_c_string(self, f):
448 text, add, output = _text_accumulator()
449 # turn docstring into a properly quoted C string
450 for line in f.docstring.split('\n'):
451 add('"')
452 add(quoted_for_c_string(line))
453 add('\\n"\n')
454
455 text.pop()
456 add('"')
457 return ''.join(text)
458
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800459 _templates = {}
460 # the templates will be run through str.format(),
461 # so actual curly-braces need to be doubled up.
462 templates_source = """
463__________________________________________________
464
465docstring_prototype
466
467PyDoc_VAR({c_basename}__doc__);
468__________________________________________________
469
470docstring_definition
471
472PyDoc_STRVAR({c_basename}__doc__,
473{docstring});
474__________________________________________________
475
476impl_definition
477
478static {impl_return_type}
479{c_basename}_impl({impl_parameters})
480__________________________________________________
481
482parser_prototype_noargs
483
484static PyObject *
485{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
486__________________________________________________
487
488parser_prototype_meth_o
489
490# SLIGHT HACK
491# METH_O uses {impl_parameters} for the parser!
492
493static PyObject *
494{c_basename}({impl_parameters})
495__________________________________________________
496
497parser_prototype_varargs
498
499static PyObject *
500{c_basename}({self_type}{self_name}, PyObject *args)
501__________________________________________________
502
503parser_prototype_keyword
504
505static PyObject *
506{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
507__________________________________________________
508
509parser_prototype_init
510
511static int
512{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
513__________________________________________________
514
515parser_definition_simple_no_parsing
516
517{{
518 return {c_basename}_impl({impl_arguments});
519}}
520__________________________________________________
521
522parser_definition_start
523
524{{
525 {return_value_declaration}
526 {declarations}
527 {initializers}
528{empty line}
529__________________________________________________
530
531parser_definition_end
532
533 {return_conversion}
534
535{exit_label}
536 {cleanup}
537 return return_value;
538}}
539__________________________________________________
540
541parser_definition_impl_call
542
543 {return_value} = {c_basename}_impl({impl_arguments});
544__________________________________________________
545
546parser_definition_unpack_tuple
547
548 if (!PyArg_UnpackTuple(args, "{name}",
549 {unpack_min}, {unpack_max},
550 {parse_arguments}))
551 goto exit;
552__________________________________________________
553
554parser_definition_parse_tuple
555
556 if (!PyArg_ParseTuple(args,
557 "{format_units}:{name}",
558 {parse_arguments}))
559 goto exit;
560__________________________________________________
561
562parser_definition_option_groups
563 {option_group_parsing}
564
565__________________________________________________
566
567parser_definition_parse_tuple_and_keywords
568
569 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
570 "{format_units}:{name}", _keywords,
571 {parse_arguments}))
572 goto exit;
573__________________________________________________
574
575parser_definition_no_positional
576
577 if (!_PyArg_NoPositional("{name}", args))
578 goto exit;
579
580__________________________________________________
581
582parser_definition_no_keywords
583
584 if (!_PyArg_NoKeywords("{name}", kwargs))
585 goto exit;
586
587__________________________________________________
588
589methoddef_define
590
591#define {methoddef_name} \\
592 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
593__________________________________________________
594""".rstrip()
595
596 title = ''
597 buffer = []
598 line = None
599 for line in templates_source.split('\n'):
600 line = line.rstrip()
601 if line.startswith('# '):
602 # comment
603 continue
604 if line.startswith("_____"):
605 if not buffer:
606 continue
607 assert title not in _templates, "defined template twice: " + repr(title)
608 buffer = '\n'.join(buffer).rstrip()
609 buffer = buffer.replace('{empty line}', '')
610 _templates[title] = buffer
611 buffer = []
612 title = ''
613 continue
614 if not title:
615 if not line:
616 continue
617 title = line
618 continue
619 if not (line or buffer):
620 # throw away leading blank lines
621 continue
622 buffer.append(line)
623
624 assert not title, 'ensure templates_source ends with ______ (still adding to ' + repr(title) + ")"
625
626 del templates_source
627 del title
628 del buffer
629 del line
630
631 # for name, value in _templates.items():
632 # print(name + ":")
633 # pprint.pprint(value)
634 # print()
Larry Hastings31826802013-10-19 00:09:25 -0700635
Larry Hastingsbebf7352014-01-17 17:47:17 -0800636 def output_templates(self, f):
637 parameters = list(f.parameters.values())
638 converters = [p.converter for p in parameters]
639
640 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
641 default_return_converter = (not f.return_converter or
642 f.return_converter.type == 'PyObject *')
643
644 positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY)
645 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
646 first_optional = len(parameters)
647 for i, p in enumerate(parameters):
648 c = p.converter
649 if type(c) != object_converter:
650 break
651 if c.format_unit != 'O':
652 break
653 if p.default is not unspecified:
654 first_optional = min(first_optional, i)
655 else:
656 all_boring_objects = True
657
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800658 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
659
Larry Hastingsbebf7352014-01-17 17:47:17 -0800660 meth_o = (len(parameters) == 1 and
661 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
662 not converters[0].is_optional() and
663 isinstance(converters[0], object_converter) and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800664 converters[0].format_unit == 'O' and
665 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800666
667 # we have to set seven things before we're done:
668 #
669 # docstring_prototype
670 # docstring_definition
671 # impl_prototype
672 # methoddef_define
673 # parser_prototype
674 # parser_definition
675 # impl_definition
Larry Hastingsbebf7352014-01-17 17:47:17 -0800676
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800677 templates = self._templates
Larry Hastingsbebf7352014-01-17 17:47:17 -0800678
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800679 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700680
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800681 methoddef_define = templates['methoddef_define']
682 docstring_prototype = templates['docstring_prototype']
683 docstring_definition = templates['docstring_definition']
684 impl_definition = templates['impl_definition']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800685 impl_prototype = parser_prototype = parser_definition = None
686
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800687 parser_body_fields = None
688 def parser_body(prototype, *fields):
689 nonlocal parser_body_fields
690 add, output = text_accumulator()
691 add(prototype)
692 parser_body_fields = fields
693 fields = list(fields)
694 fields.insert(0, 'parser_definition_start')
695 fields.append('parser_definition_impl_call')
696 fields.append('parser_definition_end')
697 for field in fields:
698 add('\n')
699 add(templates[field])
700 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800701
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800702 def insert_keywords(s):
703 return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")
Larry Hastingsbebf7352014-01-17 17:47:17 -0800704
705 if not parameters:
706 # no parameters, METH_NOARGS
707
708 flags = "METH_NOARGS"
709
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800710 parser_prototype = templates['parser_prototype_noargs']
711 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800712
713 if default_return_converter:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800714 parser_definition = parser_prototype + '\n' + templates['parser_definition_simple_no_parsing']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800715 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800716 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700717
Larry Hastingsbebf7352014-01-17 17:47:17 -0800718 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800719 flags = "METH_O"
720 # impl_definition = templates['parser_prototype_meth_o']
721
Larry Hastingsbebf7352014-01-17 17:47:17 -0800722 if default_return_converter:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800723 # maps perfectly to METH_O, doesn't need a return converter.
724 # so we skip making a parse function
725 # and call directly into the impl function.
Larry Hastingsbebf7352014-01-17 17:47:17 -0800726 impl_prototype = parser_prototype = parser_definition = ''
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800727 impl_definition = templates['parser_prototype_meth_o']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800728 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800729 parser_prototype = templates['parser_prototype_meth_o']
730 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700731
Larry Hastingsbebf7352014-01-17 17:47:17 -0800732 elif has_option_groups:
733 # positional parameters with option groups
734 # (we have to generate lots of PyArg_ParseTuple calls
735 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700736
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800737 flags = "METH_VARARGS"
738 parser_prototype = templates['parser_prototype_varargs']
Larry Hastings31826802013-10-19 00:09:25 -0700739
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800740 parser_definition = parser_body(parser_prototype, 'parser_definition_option_groups')
Larry Hastings31826802013-10-19 00:09:25 -0700741
Larry Hastingsbebf7352014-01-17 17:47:17 -0800742 elif positional and all_boring_objects:
743 # positional-only, but no option groups,
744 # and nothing but normal objects:
745 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700746
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800747 flags = "METH_VARARGS"
748 parser_prototype = templates['parser_prototype_varargs']
Larry Hastings31826802013-10-19 00:09:25 -0700749
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800750 parser_definition = parser_body(parser_prototype, 'parser_definition_unpack_tuple')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800751
752 elif positional:
753 # positional-only, but no option groups
754 # we only need one call to PyArg_ParseTuple
755
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800756 flags = "METH_VARARGS"
757 parser_prototype = templates['parser_prototype_varargs']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800758
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800759 parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800760
761 else:
762 # positional-or-keyword arguments
763 flags = "METH_VARARGS|METH_KEYWORDS"
764
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800765 parser_prototype = templates['parser_prototype_keyword']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800766
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800767 parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple_and_keywords')
768 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700769
Larry Hastings31826802013-10-19 00:09:25 -0700770
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800771 if new_or_init:
772 methoddef_define = ''
773
774 if f.kind == METHOD_NEW:
775 parser_prototype = templates['parser_prototype_keyword']
776 else:
777 return_value_declaration = "int return_value = -1;"
778 parser_prototype = templates['parser_prototype_init']
779
780 fields = list(parser_body_fields)
781 parses_positional = 'METH_NOARGS' not in flags
782 parses_keywords = 'METH_KEYWORDS' in flags
783 if parses_keywords:
784 assert parses_positional
785
786 if not parses_keywords:
787 fields.insert(0, 'parser_definition_no_keywords')
788 if not parses_positional:
789 fields.insert(0, 'parser_definition_no_positional')
790
791 parser_definition = parser_body(parser_prototype, *fields)
792 if parses_keywords:
793 parser_definition = insert_keywords(parser_definition)
794
Larry Hastings31826802013-10-19 00:09:25 -0700795
Larry Hastingsbebf7352014-01-17 17:47:17 -0800796 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800797 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700798
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800799 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700800
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800801 # add ';' to the end of parser_prototype and impl_prototype
802 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800803 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800804 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800805 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800806 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700807
Larry Hastingsbebf7352014-01-17 17:47:17 -0800808 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800809 impl_prototype = impl_definition
810 if impl_prototype:
811 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700812
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800813 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800814
815 d = {
816 "docstring_prototype" : docstring_prototype,
817 "docstring_definition" : docstring_definition,
818 "impl_prototype" : impl_prototype,
819 "methoddef_define" : methoddef_define,
820 "parser_prototype" : parser_prototype,
821 "parser_definition" : parser_definition,
822 "impl_definition" : impl_definition,
823 }
824
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800825 # make sure we didn't forget to assign something,
826 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -0800827 d2 = {}
828 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800829 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800830 if value:
831 value = '\n' + value + '\n'
832 d2[name] = value
833 return d2
Larry Hastings31826802013-10-19 00:09:25 -0700834
835 @staticmethod
836 def group_to_variable_name(group):
837 adjective = "left_" if group < 0 else "right_"
838 return "group_" + adjective + str(abs(group))
839
840 def render_option_group_parsing(self, f, template_dict):
841 # positional only, grouped, optional arguments!
842 # can be optional on the left or right.
843 # here's an example:
844 #
845 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
846 #
847 # Here group D are required, and all other groups are optional.
848 # (Group D's "group" is actually None.)
849 # We can figure out which sets of arguments we have based on
850 # how many arguments are in the tuple.
851 #
852 # Note that you need to count up on both sides. For example,
853 # you could have groups C+D, or C+D+E, or C+D+E+F.
854 #
855 # What if the number of arguments leads us to an ambiguous result?
856 # Clinic prefers groups on the left. So in the above example,
857 # five arguments would map to B+C, not C+D.
858
859 add, output = text_accumulator()
860 parameters = list(f.parameters.values())
861
862 groups = []
863 group = None
864 left = []
865 right = []
866 required = []
867 last = unspecified
868
869 for p in parameters:
870 group_id = p.group
871 if group_id != last:
872 last = group_id
873 group = []
874 if group_id < 0:
875 left.append(group)
876 elif group_id == 0:
877 group = required
878 else:
879 right.append(group)
880 group.append(p)
881
882 count_min = sys.maxsize
883 count_max = -1
884
Larry Hastings2a727912014-01-16 11:32:01 -0800885 add("switch (PyTuple_GET_SIZE(args)) {{\n")
Larry Hastings31826802013-10-19 00:09:25 -0700886 for subset in permute_optional_groups(left, required, right):
887 count = len(subset)
888 count_min = min(count_min, count)
889 count_max = max(count_max, count)
890
Larry Hastings583baa82014-01-12 08:49:30 -0800891 if count == 0:
892 add(""" case 0:
893 break;
894""")
895 continue
896
Larry Hastings31826802013-10-19 00:09:25 -0700897 group_ids = {p.group for p in subset} # eliminate duplicates
898 d = {}
899 d['count'] = count
900 d['name'] = f.name
901 d['groups'] = sorted(group_ids)
902 d['format_units'] = "".join(p.converter.format_unit for p in subset)
903
904 parse_arguments = []
905 for p in subset:
906 p.converter.parse_argument(parse_arguments)
907 d['parse_arguments'] = ", ".join(parse_arguments)
908
909 group_ids.discard(0)
910 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
911 lines = "\n".join(lines)
912
913 s = """
914 case {count}:
915 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
916 return NULL;
917 {group_booleans}
918 break;
919"""[1:]
920 s = linear_format(s, group_booleans=lines)
921 s = s.format_map(d)
922 add(s)
923
924 add(" default:\n")
925 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
926 add(s.format(f.full_name, count_min, count_max))
927 add(' return NULL;\n')
928 add("}}")
929 template_dict['option_group_parsing'] = output()
930
Larry Hastingsbebf7352014-01-17 17:47:17 -0800931 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -0700932 if not f:
933 return ""
934
935 add, output = text_accumulator()
936 data = CRenderData()
937
Larry Hastings31826802013-10-19 00:09:25 -0700938 parameters = list(f.parameters.values())
939 converters = [p.converter for p in parameters]
940
941 template_dict = {}
942
943 full_name = f.full_name
944 template_dict['full_name'] = full_name
945
946 name = full_name.rpartition('.')[2]
947 template_dict['name'] = name
948
Larry Hastings8666e652014-01-12 14:12:59 -0800949 if f.c_basename:
950 c_basename = f.c_basename
951 else:
952 fields = full_name.split(".")
953 if fields[-1] == '__new__':
954 fields.pop()
955 c_basename = "_".join(fields)
Larry Hastings31826802013-10-19 00:09:25 -0700956 template_dict['c_basename'] = c_basename
957
958 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
959 template_dict['methoddef_name'] = methoddef_name
960
961 template_dict['docstring'] = self.docstring_for_c_string(f)
962
Larry Hastings31826802013-10-19 00:09:25 -0700963 positional = has_option_groups = False
964
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800965 first_optional = len(parameters)
966
Larry Hastings31826802013-10-19 00:09:25 -0700967 if parameters:
968 last_group = 0
969
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800970 for i, p in enumerate(parameters):
Larry Hastings31826802013-10-19 00:09:25 -0700971 c = p.converter
972
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800973 if p.default is not unspecified:
974 first_optional = min(first_optional, i)
975
Larry Hastings31826802013-10-19 00:09:25 -0700976 # insert group variable
977 group = p.group
978 if last_group != group:
979 last_group = group
980 if group:
981 group_name = self.group_to_variable_name(group)
982 data.impl_arguments.append(group_name)
983 data.declarations.append("int " + group_name + " = 0;")
984 data.impl_parameters.append("int " + group_name)
985 has_option_groups = True
986 c.render(p, data)
987
988 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
Larry Hastings4a55fc52014-01-12 11:09:57 -0800989 if has_option_groups and (not positional):
990 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
Larry Hastings31826802013-10-19 00:09:25 -0700991
Larry Hastingsbebf7352014-01-17 17:47:17 -0800992 # HACK
993 # when we're METH_O, but have a custom
994 # return converter, we use
995 # "impl_parameters" for the parsing
996 # function because that works better.
997 # but that means we must supress actually
998 # declaring the impl's parameters as variables
999 # in the parsing function. but since it's
1000 # METH_O, we only have one anyway, so we don't
1001 # have any problem finding it.
1002 default_return_converter = (not f.return_converter or
1003 f.return_converter.type == 'PyObject *')
1004 if (len(parameters) == 1 and
1005 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
1006 not converters[0].is_optional() and
1007 isinstance(converters[0], object_converter) and
1008 converters[0].format_unit == 'O' and
1009 not default_return_converter):
1010
1011 data.declarations.pop(0)
1012
Larry Hastingsebdcb502013-11-23 14:54:00 -08001013 # now insert our "self" (or whatever) parameters
1014 # (we deliberately don't call render on self converters)
1015 stock_self = self_converter('self', f)
1016 template_dict['self_name'] = stock_self.name
1017 template_dict['self_type'] = stock_self.type
1018 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
1019 if f.self_converter.type != stock_self.type:
1020 self_cast = '(' + f.self_converter.type + ')'
1021 else:
1022 self_cast = ''
1023 data.impl_arguments.insert(0, self_cast + stock_self.name)
1024
Larry Hastings31826802013-10-19 00:09:25 -07001025 f.return_converter.render(f, data)
1026 template_dict['impl_return_type'] = f.return_converter.type
1027
1028 template_dict['declarations'] = "\n".join(data.declarations)
1029 template_dict['initializers'] = "\n\n".join(data.initializers)
1030 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1031 template_dict['format_units'] = ''.join(data.format_units)
1032 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1033 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1034 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
1035 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
1036 template_dict['cleanup'] = "".join(data.cleanup)
1037 template_dict['return_value'] = data.return_value
1038
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001039 # used by unpack tuple
1040 template_dict['unpack_min'] = str(first_optional)
1041 template_dict['unpack_max'] = str(len(parameters))
1042
Larry Hastingsbebf7352014-01-17 17:47:17 -08001043 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001044 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001045
1046 templates = self.output_templates(f)
1047
1048 for name, destination in clinic.field_destinations.items():
1049 template = templates[name]
1050 if has_option_groups:
1051 template = linear_format(template,
1052 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001053 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001054 declarations=template_dict['declarations'],
1055 return_conversion=template_dict['return_conversion'],
1056 initializers=template_dict['initializers'],
1057 cleanup=template_dict['cleanup'],
1058 )
Larry Hastings31826802013-10-19 00:09:25 -07001059
Larry Hastingsbebf7352014-01-17 17:47:17 -08001060 # Only generate the "exit:" label
1061 # if we have any gotos
1062 need_exit_label = "goto exit;" in template
1063 template = linear_format(template,
1064 exit_label="exit:" if need_exit_label else ''
1065 )
Larry Hastings31826802013-10-19 00:09:25 -07001066
Larry Hastingsbebf7352014-01-17 17:47:17 -08001067 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001068
Larry Hastingsbebf7352014-01-17 17:47:17 -08001069 if clinic.line_prefix:
1070 s = indent_all_lines(s, clinic.line_prefix)
1071 if clinic.line_suffix:
1072 s = suffix_all_lines(s, clinic.line_suffix)
1073
1074 destination.append(s)
1075
1076 return clinic.get_destination('block').dump()
1077
Larry Hastings31826802013-10-19 00:09:25 -07001078
1079
1080@contextlib.contextmanager
1081def OverrideStdioWith(stdout):
1082 saved_stdout = sys.stdout
1083 sys.stdout = stdout
1084 try:
1085 yield
1086 finally:
1087 assert sys.stdout is stdout
1088 sys.stdout = saved_stdout
1089
1090
1091def create_regex(before, after):
1092 """Create an re object for matching marker lines."""
1093 pattern = r'^{}(\w+){}$'
1094 return re.compile(pattern.format(re.escape(before), re.escape(after)))
1095
1096
1097class Block:
1098 r"""
1099 Represents a single block of text embedded in
1100 another file. If dsl_name is None, the block represents
1101 verbatim text, raw original text from the file, in
1102 which case "input" will be the only non-false member.
1103 If dsl_name is not None, the block represents a Clinic
1104 block.
1105
1106 input is always str, with embedded \n characters.
1107 input represents the original text from the file;
1108 if it's a Clinic block, it is the original text with
1109 the body_prefix and redundant leading whitespace removed.
1110
1111 dsl_name is either str or None. If str, it's the text
1112 found on the start line of the block between the square
1113 brackets.
1114
1115 signatures is either list or None. If it's a list,
1116 it may only contain clinic.Module, clinic.Class, and
1117 clinic.Function objects. At the moment it should
1118 contain at most one of each.
1119
1120 output is either str or None. If str, it's the output
1121 from this block, with embedded '\n' characters.
1122
1123 indent is either str or None. It's the leading whitespace
1124 that was found on every line of input. (If body_prefix is
1125 not empty, this is the indent *after* removing the
1126 body_prefix.)
1127
1128 preindent is either str or None. It's the whitespace that
1129 was found in front of every line of input *before* the
1130 "body_prefix" (see the Language object). If body_prefix
1131 is empty, preindent must always be empty too.
1132
1133 To illustrate indent and preindent: Assume that '_'
1134 represents whitespace. If the block processed was in a
1135 Python file, and looked like this:
1136 ____#/*[python]
1137 ____#__for a in range(20):
1138 ____#____print(a)
1139 ____#[python]*/
1140 "preindent" would be "____" and "indent" would be "__".
1141
1142 """
1143 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1144 assert isinstance(input, str)
1145 self.input = input
1146 self.dsl_name = dsl_name
1147 self.signatures = signatures or []
1148 self.output = output
1149 self.indent = indent
1150 self.preindent = preindent
1151
1152
1153class BlockParser:
1154 """
1155 Block-oriented parser for Argument Clinic.
1156 Iterator, yields Block objects.
1157 """
1158
1159 def __init__(self, input, language, *, verify=True):
1160 """
1161 "input" should be a str object
1162 with embedded \n characters.
1163
1164 "language" should be a Language object.
1165 """
1166 language.validate()
1167
1168 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1169 self.block_start_line_number = self.line_number = 0
1170
1171 self.language = language
1172 before, _, after = language.start_line.partition('{dsl_name}')
1173 assert _ == '{dsl_name}'
1174 self.start_re = create_regex(before, after)
1175 self.verify = verify
1176 self.last_checksum_re = None
1177 self.last_dsl_name = None
1178 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001179 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001180
1181 def __iter__(self):
1182 return self
1183
1184 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001185 while True:
1186 if not self.input:
1187 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001188
Larry Hastingsbebf7352014-01-17 17:47:17 -08001189 if self.dsl_name:
1190 return_value = self.parse_clinic_block(self.dsl_name)
1191 self.dsl_name = None
1192 self.first_block = False
1193 return return_value
1194 block = self.parse_verbatim_block()
1195 if self.first_block and not block.input:
1196 continue
1197 self.first_block = False
1198 return block
1199
Larry Hastings31826802013-10-19 00:09:25 -07001200
1201 def is_start_line(self, line):
1202 match = self.start_re.match(line.lstrip())
1203 return match.group(1) if match else None
1204
1205 def _line(self):
1206 self.line_number += 1
1207 return self.input.pop()
1208
1209 def parse_verbatim_block(self):
1210 add, output = text_accumulator()
1211 self.block_start_line_number = self.line_number
1212
1213 while self.input:
1214 line = self._line()
1215 dsl_name = self.is_start_line(line)
1216 if dsl_name:
1217 self.dsl_name = dsl_name
1218 break
1219 add(line)
1220
1221 return Block(output())
1222
1223 def parse_clinic_block(self, dsl_name):
1224 input_add, input_output = text_accumulator()
1225 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001226 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001227 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1228
Larry Hastings90261132014-01-07 12:21:08 -08001229 def is_stop_line(line):
1230 # make sure to recognize stop line even if it
1231 # doesn't end with EOL (it could be the very end of the file)
1232 if not line.startswith(stop_line):
1233 return False
1234 remainder = line[len(stop_line):]
1235 return (not remainder) or remainder.isspace()
1236
Larry Hastings31826802013-10-19 00:09:25 -07001237 # consume body of program
1238 while self.input:
1239 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001240 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001241 break
1242 if body_prefix:
1243 line = line.lstrip()
1244 assert line.startswith(body_prefix)
1245 line = line[len(body_prefix):]
1246 input_add(line)
1247
1248 # consume output and checksum line, if present.
1249 if self.last_dsl_name == dsl_name:
1250 checksum_re = self.last_checksum_re
1251 else:
1252 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
1253 assert _ == '{checksum}'
1254 checksum_re = create_regex(before, after)
1255 self.last_dsl_name = dsl_name
1256 self.last_checksum_re = checksum_re
1257
1258 # scan forward for checksum line
1259 output_add, output_output = text_accumulator()
1260 checksum = None
1261 while self.input:
1262 line = self._line()
1263 match = checksum_re.match(line.lstrip())
1264 checksum = match.group(1) if match else None
1265 if checksum:
1266 break
1267 output_add(line)
1268 if self.is_start_line(line):
1269 break
1270
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001271 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -07001272 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -07001273 if self.verify:
1274 computed = compute_checksum(output)
1275 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001276 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1277 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001278 "the end marker,\n"
1279 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001280 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001281 else:
1282 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001283 output_lines = output.splitlines(keepends=True)
1284 self.line_number -= len(output_lines)
1285 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001286 output = None
1287
1288 return Block(input_output(), dsl_name, output=output)
1289
1290
1291class BlockPrinter:
1292
1293 def __init__(self, language, f=None):
1294 self.language = language
1295 self.f = f or io.StringIO()
1296
1297 def print_block(self, block):
1298 input = block.input
1299 output = block.output
1300 dsl_name = block.dsl_name
1301 write = self.f.write
1302
Larry Hastings31826802013-10-19 00:09:25 -07001303 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1304
1305 if not dsl_name:
1306 write(input)
1307 return
1308
1309 write(self.language.start_line.format(dsl_name=dsl_name))
1310 write("\n")
1311
1312 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1313 if not body_prefix:
1314 write(input)
1315 else:
1316 for line in input.split('\n'):
1317 write(body_prefix)
1318 write(line)
1319 write("\n")
1320
1321 write(self.language.stop_line.format(dsl_name=dsl_name))
1322 write("\n")
1323
Larry Hastingsbebf7352014-01-17 17:47:17 -08001324 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001325 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001326 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001327 output += '\n'
1328 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001329
1330 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
1331 write("\n")
1332
Larry Hastingsbebf7352014-01-17 17:47:17 -08001333 def write(self, text):
1334 self.f.write(text)
1335
1336
1337class Destination:
1338 def __init__(self, name, type, clinic, *args):
1339 self.name = name
1340 self.type = type
1341 self.clinic = clinic
1342 valid_types = ('buffer', 'file', 'suppress', 'two-pass')
1343 if type not in valid_types:
1344 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1345 extra_arguments = 1 if type == "file" else 0
1346 if len(args) < extra_arguments:
1347 fail("Not enough arguments for destination " + name + " new " + type)
1348 if len(args) > extra_arguments:
1349 fail("Too many arguments for destination " + name + " new " + type)
1350 if type =='file':
1351 d = {}
1352 d['filename'] = filename = clinic.filename
1353 d['basename'], d['extension'] = os.path.splitext(filename)
1354 self.filename = args[0].format_map(d)
1355 if type == 'two-pass':
1356 self.id = None
1357
1358 self.text, self.append, self._dump = _text_accumulator()
1359
1360 def __repr__(self):
1361 if self.type == 'file':
1362 file_repr = " " + repr(self.filename)
1363 else:
1364 file_repr = ''
1365 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1366
1367 def clear(self):
1368 if self.type != 'buffer':
1369 fail("Can't clear destination" + self.name + " , it's not of type buffer")
1370 self.text.clear()
1371
1372 def dump(self):
1373 if self.type == 'two-pass':
1374 if self.id is None:
1375 self.id = str(uuid.uuid4())
1376 return self.id
1377 fail("You can only dump a two-pass buffer exactly once!")
1378 return self._dump()
1379
Larry Hastings31826802013-10-19 00:09:25 -07001380
1381# maps strings to Language objects.
1382# "languages" maps the name of the language ("C", "Python").
1383# "extensions" maps the file extension ("c", "py").
1384languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001385extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1386extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001387
1388
1389# maps strings to callables.
1390# these callables must be of the form:
1391# def foo(name, default, *, ...)
1392# The callable may have any number of keyword-only parameters.
1393# The callable must return a CConverter object.
1394# The callable should not call builtins.print.
1395converters = {}
1396
1397# maps strings to callables.
1398# these callables follow the same rules as those for "converters" above.
1399# note however that they will never be called with keyword-only parameters.
1400legacy_converters = {}
1401
1402
1403# maps strings to callables.
1404# these callables must be of the form:
1405# def foo(*, ...)
1406# The callable may have any number of keyword-only parameters.
1407# The callable must return a CConverter object.
1408# The callable should not call builtins.print.
1409return_converters = {}
1410
1411class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001412
1413 presets_text = """
1414preset original
1415everything block
1416docstring_prototype suppress
1417parser_prototype suppress
1418
1419preset file
1420everything file
1421docstring_prototype suppress
1422parser_prototype suppress
1423impl_definition block
1424
1425preset buffer
1426everything buffer
1427docstring_prototype suppress
1428impl_prototype suppress
1429parser_prototype suppress
1430impl_definition block
1431
1432preset partial-buffer
1433everything buffer
1434docstring_prototype block
1435impl_prototype suppress
1436methoddef_define block
1437parser_prototype block
1438impl_definition block
1439
1440preset two-pass
1441everything buffer
1442docstring_prototype two-pass
1443impl_prototype suppress
1444methoddef_define two-pass
1445parser_prototype two-pass
1446impl_definition block
1447
1448"""
1449
Larry Hastings31826802013-10-19 00:09:25 -07001450 def __init__(self, language, printer=None, *, verify=True, filename=None):
1451 # maps strings to Parser objects.
1452 # (instantiated from the "parsers" global.)
1453 self.parsers = {}
1454 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001455 if printer:
1456 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001457 self.printer = printer or BlockPrinter(language)
1458 self.verify = verify
1459 self.filename = filename
1460 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001461 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001462 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001463
Larry Hastingsbebf7352014-01-17 17:47:17 -08001464 self.line_prefix = self.line_suffix = ''
1465
1466 self.destinations = {}
1467 self.add_destination("block", "buffer")
1468 self.add_destination("suppress", "suppress")
1469 self.add_destination("buffer", "buffer")
1470 self.add_destination("two-pass", "two-pass")
1471 if filename:
1472 self.add_destination("file", "file", "{basename}.clinic{extension}")
1473
1474 d = self.destinations.get
1475 self.field_destinations = collections.OrderedDict((
1476 ('docstring_prototype', d('suppress')),
1477 ('docstring_definition', d('block')),
1478 ('methoddef_define', d('block')),
1479 ('impl_prototype', d('block')),
1480 ('parser_prototype', d('suppress')),
1481 ('parser_definition', d('block')),
1482 ('impl_definition', d('block')),
1483 ))
1484
1485 self.field_destinations_stack = []
1486
1487 self.presets = {}
1488 preset = None
1489 for line in self.presets_text.strip().split('\n'):
1490 line = line.strip()
1491 if not line:
1492 continue
1493 name, value = line.split()
1494 if name == 'preset':
1495 self.presets[value] = preset = collections.OrderedDict()
1496 continue
1497
1498 destination = self.get_destination(value)
1499
1500 if name == 'everything':
1501 for name in self.field_destinations:
1502 preset[name] = destination
1503 continue
1504
1505 assert name in self.field_destinations
1506 preset[name] = destination
1507
Larry Hastings31826802013-10-19 00:09:25 -07001508 global clinic
1509 clinic = self
1510
Larry Hastingsbebf7352014-01-17 17:47:17 -08001511 def get_destination(self, name, default=unspecified):
1512 d = self.destinations.get(name)
1513 if not d:
1514 if default is not unspecified:
1515 return default
1516 fail("Destination does not exist: " + repr(name))
1517 return d
1518
1519 def add_destination(self, name, type, *args):
1520 if name in self.destinations:
1521 fail("Destination already exists: " + repr(name))
1522 self.destinations[name] = Destination(name, type, self, *args)
1523
Larry Hastings31826802013-10-19 00:09:25 -07001524 def parse(self, input):
1525 printer = self.printer
1526 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1527 for block in self.block_parser:
1528 dsl_name = block.dsl_name
1529 if dsl_name:
1530 if dsl_name not in self.parsers:
1531 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1532 self.parsers[dsl_name] = parsers[dsl_name](self)
1533 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001534 try:
1535 parser.parse(block)
1536 except Exception:
1537 fail('Exception raised during parsing:\n' +
1538 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001539 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001540
1541 second_pass_replacements = {}
1542
1543 for name, destination in self.destinations.items():
1544 if destination.type == 'suppress':
1545 continue
1546 output = destination._dump()
1547
1548 if destination.type == 'two-pass':
1549 if destination.id:
1550 second_pass_replacements[destination.id] = output
1551 elif output:
1552 fail("Two-pass buffer " + repr(name) + " not empty at end of file!")
1553 continue
1554
1555 if output:
1556
1557 block = Block("", dsl_name="clinic", output=output)
1558
1559 if destination.type == 'buffer':
1560 block.input = "dump " + name + "\n"
1561 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1562 printer.write("\n")
1563 printer.print_block(block)
1564 continue
1565
1566 if destination.type == 'file':
1567 try:
1568 with open(destination.filename, "rt") as f:
1569 parser_2 = BlockParser(f.read(), language=self.language)
1570 blocks = list(parser_2)
1571 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1572 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
1573 except FileNotFoundError:
1574 pass
1575
1576 block.input = 'preserve\n'
1577 printer_2 = BlockPrinter(self.language)
1578 printer_2.print_block(block)
1579 with open(destination.filename, "wt") as f:
1580 f.write(printer_2.f.getvalue())
1581 continue
1582 text = printer.f.getvalue()
1583
1584 if second_pass_replacements:
1585 printer_2 = BlockPrinter(self.language)
1586 parser_2 = BlockParser(text, self.language)
1587 changed = False
1588 for block in parser_2:
1589 if block.dsl_name:
1590 for id, replacement in second_pass_replacements.items():
1591 if id in block.output:
1592 changed = True
1593 block.output = block.output.replace(id, replacement)
1594 printer_2.print_block(block)
1595 if changed:
1596 text = printer_2.f.getvalue()
1597
1598 return text
1599
Larry Hastings31826802013-10-19 00:09:25 -07001600
1601 def _module_and_class(self, fields):
1602 """
1603 fields should be an iterable of field names.
1604 returns a tuple of (module, class).
1605 the module object could actually be self (a clinic object).
1606 this function is only ever used to find the parent of where
1607 a new class/module should go.
1608 """
1609 in_classes = False
1610 parent = module = self
1611 cls = None
1612 so_far = []
1613
1614 for field in fields:
1615 so_far.append(field)
1616 if not in_classes:
1617 child = parent.modules.get(field)
1618 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001619 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001620 continue
1621 in_classes = True
1622 if not hasattr(parent, 'classes'):
1623 return module, cls
1624 child = parent.classes.get(field)
1625 if not child:
1626 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1627 cls = parent = child
1628
1629 return module, cls
1630
1631
1632def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1633 extension = os.path.splitext(filename)[1][1:]
1634 if not extension:
1635 fail("Can't extract file type for file " + repr(filename))
1636
1637 try:
1638 language = extensions[extension]()
1639 except KeyError:
1640 fail("Can't identify file type for file " + repr(filename))
1641
1642 clinic = Clinic(language, verify=verify, filename=filename)
1643
1644 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001645 raw = f.read()
1646
1647 cooked = clinic.parse(raw)
1648 if cooked == raw:
1649 return
Larry Hastings31826802013-10-19 00:09:25 -07001650
1651 directory = os.path.dirname(filename) or '.'
1652
1653 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001654 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001655 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1656 with open(tmpfilename, "wb") as f:
1657 f.write(bytes)
1658 os.replace(tmpfilename, output or filename)
1659
1660
1661def compute_checksum(input):
1662 input = input or ''
1663 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1664
1665
1666
1667
1668class PythonParser:
1669 def __init__(self, clinic):
1670 pass
1671
1672 def parse(self, block):
1673 s = io.StringIO()
1674 with OverrideStdioWith(s):
1675 exec(block.input)
1676 block.output = s.getvalue()
1677
1678
1679class Module:
1680 def __init__(self, name, module=None):
1681 self.name = name
1682 self.module = self.parent = module
1683
1684 self.modules = collections.OrderedDict()
1685 self.classes = collections.OrderedDict()
1686 self.functions = []
1687
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001688 def __repr__(self):
1689 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1690
Larry Hastings31826802013-10-19 00:09:25 -07001691class Class:
1692 def __init__(self, name, module=None, cls=None):
1693 self.name = name
1694 self.module = module
1695 self.cls = cls
1696 self.parent = cls or module
1697
1698 self.classes = collections.OrderedDict()
1699 self.functions = []
1700
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001701 def __repr__(self):
1702 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1703
Larry Hastings8666e652014-01-12 14:12:59 -08001704unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001705
Larry Hastings8666e652014-01-12 14:12:59 -08001706__abs__
1707__add__
1708__and__
1709__bytes__
1710__call__
1711__complex__
1712__delitem__
1713__divmod__
1714__eq__
1715__float__
1716__floordiv__
1717__ge__
1718__getattr__
1719__getattribute__
1720__getitem__
1721__gt__
1722__hash__
1723__iadd__
1724__iand__
1725__idivmod__
1726__ifloordiv__
1727__ilshift__
1728__imod__
1729__imul__
1730__index__
1731__int__
1732__invert__
1733__ior__
1734__ipow__
1735__irshift__
1736__isub__
1737__iter__
1738__itruediv__
1739__ixor__
1740__le__
1741__len__
1742__lshift__
1743__lt__
1744__mod__
1745__mul__
1746__neg__
1747__new__
1748__next__
1749__or__
1750__pos__
1751__pow__
1752__radd__
1753__rand__
1754__rdivmod__
1755__repr__
1756__rfloordiv__
1757__rlshift__
1758__rmod__
1759__rmul__
1760__ror__
1761__round__
1762__rpow__
1763__rrshift__
1764__rshift__
1765__rsub__
1766__rtruediv__
1767__rxor__
1768__setattr__
1769__setitem__
1770__str__
1771__sub__
1772__truediv__
1773__xor__
1774
1775""".strip().split())
1776
1777
1778INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6)
Larry Hastings31826802013-10-19 00:09:25 -07001779
1780class Function:
1781 """
1782 Mutable duck type for inspect.Function.
1783
1784 docstring - a str containing
1785 * embedded line breaks
1786 * text outdented to the left margin
1787 * no trailing whitespace.
1788 It will always be true that
1789 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1790 """
1791
1792 def __init__(self, parameters=None, *, name,
1793 module, cls=None, c_basename=None,
1794 full_name=None,
1795 return_converter, return_annotation=_empty,
1796 docstring=None, kind=CALLABLE, coexist=False):
1797 self.parameters = parameters or collections.OrderedDict()
1798 self.return_annotation = return_annotation
1799 self.name = name
1800 self.full_name = full_name
1801 self.module = module
1802 self.cls = cls
1803 self.parent = cls or module
1804 self.c_basename = c_basename
1805 self.return_converter = return_converter
1806 self.docstring = docstring or ''
1807 self.kind = kind
1808 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001809 self.self_converter = None
1810
1811 @property
1812 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001813 if self.kind in (METHOD_INIT, METHOD_NEW):
1814 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001815 flags = []
1816 if self.kind == CLASS_METHOD:
1817 flags.append('METH_CLASS')
1818 elif self.kind == STATIC_METHOD:
1819 flags.append('METH_STATIC')
1820 else:
1821 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1822 if self.coexist:
1823 flags.append('METH_COEXIST')
1824 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001825
1826 def __repr__(self):
1827 return '<clinic.Function ' + self.name + '>'
1828
1829
1830class Parameter:
1831 """
1832 Mutable duck type of inspect.Parameter.
1833 """
1834
1835 def __init__(self, name, kind, *, default=_empty,
1836 function, converter, annotation=_empty,
1837 docstring=None, group=0):
1838 self.name = name
1839 self.kind = kind
1840 self.default = default
1841 self.function = function
1842 self.converter = converter
1843 self.annotation = annotation
1844 self.docstring = docstring or ''
1845 self.group = group
1846
1847 def __repr__(self):
1848 return '<clinic.Parameter ' + self.name + '>'
1849
1850 def is_keyword_only(self):
1851 return self.kind == inspect.Parameter.KEYWORD_ONLY
1852
Larry Hastings31826802013-10-19 00:09:25 -07001853
Larry Hastings31826802013-10-19 00:09:25 -07001854
1855def add_c_converter(f, name=None):
1856 if not name:
1857 name = f.__name__
1858 if not name.endswith('_converter'):
1859 return f
1860 name = name[:-len('_converter')]
1861 converters[name] = f
1862 return f
1863
1864def add_default_legacy_c_converter(cls):
1865 # automatically add converter for default format unit
1866 # (but without stomping on the existing one if it's already
1867 # set, in case you subclass)
1868 if ((cls.format_unit != 'O&') and
1869 (cls.format_unit not in legacy_converters)):
1870 legacy_converters[cls.format_unit] = cls
1871 return cls
1872
1873def add_legacy_c_converter(format_unit, **kwargs):
1874 """
1875 Adds a legacy converter.
1876 """
1877 def closure(f):
1878 if not kwargs:
1879 added_f = f
1880 else:
1881 added_f = functools.partial(f, **kwargs)
1882 legacy_converters[format_unit] = added_f
1883 return f
1884 return closure
1885
1886class CConverterAutoRegister(type):
1887 def __init__(cls, name, bases, classdict):
1888 add_c_converter(cls)
1889 add_default_legacy_c_converter(cls)
1890
1891class CConverter(metaclass=CConverterAutoRegister):
1892 """
1893 For the init function, self, name, function, and default
1894 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08001895 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07001896 """
1897
Larry Hastings78cf85c2014-01-04 12:44:57 -08001898 # The C type to use for this variable.
1899 # 'type' should be a Python string specifying the type, e.g. "int".
1900 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001901 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001902
1903 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001904 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08001905 # Or the magic value "unknown" if this value is a cannot be evaluated
1906 # at Argument-Clinic-preprocessing time (but is presumed to be valid
1907 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07001908 default = unspecified
1909
Larry Hastings4a55fc52014-01-12 11:09:57 -08001910 # If not None, default must be isinstance() of this type.
1911 # (You can also specify a tuple of types.)
1912 default_type = None
1913
Larry Hastings31826802013-10-19 00:09:25 -07001914 # "default" converted into a C value, as a string.
1915 # Or None if there is no default.
1916 c_default = None
1917
Larry Hastings2a727912014-01-16 11:32:01 -08001918 # "default" converted into a Python value, as a string.
1919 # Or None if there is no default.
1920 py_default = None
1921
Larry Hastingsabc716b2013-11-20 09:13:52 -08001922 # The default value used to initialize the C variable when
1923 # there is no default, but not specifying a default may
1924 # result in an "uninitialized variable" warning. This can
1925 # easily happen when using option groups--although
1926 # properly-written code won't actually use the variable,
1927 # the variable does get passed in to the _impl. (Ah, if
1928 # only dataflow analysis could inline the static function!)
1929 #
1930 # This value is specified as a string.
1931 # Every non-abstract subclass should supply a valid value.
1932 c_ignored_default = 'NULL'
1933
Larry Hastings31826802013-10-19 00:09:25 -07001934 # The C converter *function* to be used, if any.
1935 # (If this is not None, format_unit must be 'O&'.)
1936 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001937
Larry Hastings78cf85c2014-01-04 12:44:57 -08001938 # Should Argument Clinic add a '&' before the name of
1939 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001940 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001941
1942 # Should Argument Clinic add a '&' before the name of
1943 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001944 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001945
1946 #############################################################
1947 #############################################################
1948 ## You shouldn't need to read anything below this point to ##
1949 ## write your own converter functions. ##
1950 #############################################################
1951 #############################################################
1952
1953 # The "format unit" to specify for this variable when
1954 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1955 # Custom converters should always use the default value of 'O&'.
1956 format_unit = 'O&'
1957
1958 # What encoding do we want for this variable? Only used
1959 # by format units starting with 'e'.
1960 encoding = None
1961
Larry Hastings77561cc2014-01-07 12:13:13 -08001962 # Should this object be required to be a subclass of a specific type?
1963 # If not None, should be a string representing a pointer to a
1964 # PyTypeObject (e.g. "&PyUnicode_Type").
1965 # Only used by the 'O!' format unit (and the "object" converter).
1966 subclass_of = None
1967
Larry Hastings78cf85c2014-01-04 12:44:57 -08001968 # Do we want an adjacent '_length' variable for this variable?
1969 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001970 length = False
1971
Larry Hastings2a727912014-01-16 11:32:01 -08001972 def __init__(self, name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Larry Hastings31826802013-10-19 00:09:25 -07001973 self.function = function
1974 self.name = name
1975
1976 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08001977 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08001978 if isinstance(self.default_type, type):
1979 types_str = self.default_type.__name__
1980 else:
1981 types_str = ', '.join((cls.__name__ for cls in self.default_type))
1982 fail("{}: default value {!r} for field {} is not of type {}".format(
1983 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07001984 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08001985
Larry Hastingsb4705752014-01-18 21:54:15 -08001986 if c_default:
1987 self.c_default = c_default
1988 if py_default:
1989 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08001990
Larry Hastings31826802013-10-19 00:09:25 -07001991 if annotation != unspecified:
1992 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings31826802013-10-19 00:09:25 -07001993 self.converter_init(**kwargs)
1994
1995 def converter_init(self):
1996 pass
1997
1998 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08001999 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002000
2001 def render(self, parameter, data):
2002 """
2003 parameter is a clinic.Parameter instance.
2004 data is a CRenderData instance.
2005 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08002006 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002007 original_name = self.name
2008 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002009
2010 # declarations
2011 d = self.declaration()
2012 data.declarations.append(d)
2013
2014 # initializers
2015 initializers = self.initialize()
2016 if initializers:
2017 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2018
2019 # impl_arguments
2020 s = ("&" if self.impl_by_reference else "") + name
2021 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002022 if self.length:
2023 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07002024
2025 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08002026 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002027
2028 # format_units
2029 if self.is_optional() and '|' not in data.format_units:
2030 data.format_units.append('|')
2031 if parameter.is_keyword_only() and '$' not in data.format_units:
2032 data.format_units.append('$')
2033 data.format_units.append(self.format_unit)
2034
2035 # parse_arguments
2036 self.parse_argument(data.parse_arguments)
2037
2038 # impl_parameters
2039 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08002040 if self.length:
2041 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07002042
2043 # cleanup
2044 cleanup = self.cleanup()
2045 if cleanup:
2046 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2047
Larry Hastingsebdcb502013-11-23 14:54:00 -08002048 def length_name(self):
2049 """Computes the name of the associated "length" variable."""
2050 if not self.length:
2051 return None
2052 return ensure_legal_c_identifier(self.name) + "_length"
2053
Larry Hastings31826802013-10-19 00:09:25 -07002054 # Why is this one broken out separately?
2055 # For "positional-only" function parsing,
2056 # which generates a bunch of PyArg_ParseTuple calls.
2057 def parse_argument(self, list):
2058 assert not (self.converter and self.encoding)
2059 if self.format_unit == 'O&':
2060 assert self.converter
2061 list.append(self.converter)
2062
2063 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002064 list.append(c_repr(self.encoding))
2065 elif self.subclass_of:
2066 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002067
Larry Hastingsebdcb502013-11-23 14:54:00 -08002068 legal_name = ensure_legal_c_identifier(self.name)
2069 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002070 list.append(s)
2071
Larry Hastingsebdcb502013-11-23 14:54:00 -08002072 if self.length:
2073 list.append("&" + self.length_name())
2074
Larry Hastings31826802013-10-19 00:09:25 -07002075 #
2076 # All the functions after here are intended as extension points.
2077 #
2078
2079 def simple_declaration(self, by_reference=False):
2080 """
2081 Computes the basic declaration of the variable.
2082 Used in computing the prototype declaration and the
2083 variable declaration.
2084 """
2085 prototype = [self.type]
2086 if by_reference or not self.type.endswith('*'):
2087 prototype.append(" ")
2088 if by_reference:
2089 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002090 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002091 return "".join(prototype)
2092
2093 def declaration(self):
2094 """
2095 The C statement to declare this variable.
2096 """
2097 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002098 default = self.c_default
2099 if not default and self.parameter.group:
2100 default = self.c_ignored_default
2101 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002102 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002103 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002104 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002105 if self.length:
2106 declaration.append('\nPy_ssize_clean_t ')
2107 declaration.append(self.length_name())
2108 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08002109 s = "".join(declaration)
2110 # double up curly-braces, this string will be used
2111 # as part of a format_map() template later
2112 s = s.replace("{", "{{")
2113 s = s.replace("}", "}}")
2114 return s
Larry Hastings31826802013-10-19 00:09:25 -07002115
2116 def initialize(self):
2117 """
2118 The C statements required to set up this variable before parsing.
2119 Returns a string containing this code indented at column 0.
2120 If no initialization is necessary, returns an empty string.
2121 """
2122 return ""
2123
2124 def cleanup(self):
2125 """
2126 The C statements required to clean up after this variable.
2127 Returns a string containing this code indented at column 0.
2128 If no cleanup is necessary, returns an empty string.
2129 """
2130 return ""
2131
2132
2133class bool_converter(CConverter):
2134 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002135 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002136 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002137 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002138
2139 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002140 if self.default is not unspecified:
2141 self.default = bool(self.default)
2142 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002143
2144class char_converter(CConverter):
2145 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002146 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07002147 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002148 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002149
Larry Hastings4a55fc52014-01-12 11:09:57 -08002150 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002151 if isinstance(self.default, str) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002152 fail("char_converter: illegal default value " + repr(self.default))
2153
2154
Larry Hastings31826802013-10-19 00:09:25 -07002155@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002156class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002157 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002158 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002159 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002160 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002161
2162 def converter_init(self, *, bitwise=False):
2163 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002164 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002165
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002166class byte_converter(unsigned_char_converter): pass
2167
Larry Hastings31826802013-10-19 00:09:25 -07002168class short_converter(CConverter):
2169 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002170 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002171 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002172 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002173
2174class unsigned_short_converter(CConverter):
2175 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002176 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002177 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002178 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002179
2180 def converter_init(self, *, bitwise=False):
2181 if not bitwise:
2182 fail("Unsigned shorts must be bitwise (for now).")
2183
Larry Hastingsebdcb502013-11-23 14:54:00 -08002184@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07002185class int_converter(CConverter):
2186 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002187 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002188 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002189 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002190
Larry Hastingsebdcb502013-11-23 14:54:00 -08002191 def converter_init(self, *, types='int'):
2192 if types == 'str':
2193 self.format_unit = 'C'
2194 elif types != 'int':
2195 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07002196
2197class unsigned_int_converter(CConverter):
2198 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002199 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002200 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002201 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002202
2203 def converter_init(self, *, bitwise=False):
2204 if not bitwise:
2205 fail("Unsigned ints must be bitwise (for now).")
2206
2207class long_converter(CConverter):
2208 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002209 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002210 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002211 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002212
2213class unsigned_long_converter(CConverter):
2214 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002215 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002216 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002217 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002218
2219 def converter_init(self, *, bitwise=False):
2220 if not bitwise:
2221 fail("Unsigned longs must be bitwise (for now).")
2222
2223class PY_LONG_LONG_converter(CConverter):
2224 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002225 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002226 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002227 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002228
2229class unsigned_PY_LONG_LONG_converter(CConverter):
2230 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002231 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002232 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002233 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002234
2235 def converter_init(self, *, bitwise=False):
2236 if not bitwise:
2237 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
2238
2239class Py_ssize_t_converter(CConverter):
2240 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002241 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002242 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002243 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002244
2245
2246class float_converter(CConverter):
2247 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002248 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002249 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002250 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002251
2252class double_converter(CConverter):
2253 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002254 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002255 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002256 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002257
2258
2259class Py_complex_converter(CConverter):
2260 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002261 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002262 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002263 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002264
2265
2266class object_converter(CConverter):
2267 type = 'PyObject *'
2268 format_unit = 'O'
2269
Larry Hastings4a55fc52014-01-12 11:09:57 -08002270 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2271 if converter:
2272 if subclass_of:
2273 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2274 self.format_unit = 'O&'
2275 self.converter = converter
2276 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002277 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002278 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002279
Larry Hastings77561cc2014-01-07 12:13:13 -08002280 if type is not None:
2281 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002282
2283
Larry Hastingsebdcb502013-11-23 14:54:00 -08002284@add_legacy_c_converter('s#', length=True)
Larry Hastings2a727912014-01-16 11:32:01 -08002285@add_legacy_c_converter('y', types="bytes")
2286@add_legacy_c_converter('y#', types="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002287@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002288@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002289class str_converter(CConverter):
2290 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002291 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002292 format_unit = 's'
2293
Larry Hastingsebdcb502013-11-23 14:54:00 -08002294 def converter_init(self, *, encoding=None, types="str",
2295 length=False, nullable=False, zeroes=False):
2296
2297 types = set(types.strip().split())
2298 bytes_type = set(("bytes",))
2299 str_type = set(("str",))
2300 all_3_type = set(("bytearray",)) | bytes_type | str_type
2301 is_bytes = types == bytes_type
2302 is_str = types == str_type
2303 is_all_3 = types == all_3_type
2304
2305 self.length = bool(length)
2306 format_unit = None
2307
2308 if encoding:
2309 self.encoding = encoding
2310
2311 if is_str and not (length or zeroes or nullable):
2312 format_unit = 'es'
2313 elif is_all_3 and not (length or zeroes or nullable):
2314 format_unit = 'et'
2315 elif is_str and length and zeroes and not nullable:
2316 format_unit = 'es#'
2317 elif is_all_3 and length and not (nullable or zeroes):
2318 format_unit = 'et#'
2319
2320 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08002321 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002322 # TODO set pointer to NULL
2323 # TODO add cleanup for buffer
2324 pass
2325
2326 else:
2327 if zeroes:
2328 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
2329
2330 if is_bytes and not (nullable or length):
2331 format_unit = 'y'
2332 elif is_bytes and length and not nullable:
2333 format_unit = 'y#'
2334 elif is_str and not (nullable or length):
2335 format_unit = 's'
2336 elif is_str and length and not nullable:
2337 format_unit = 's#'
2338 elif is_str and nullable and not length:
2339 format_unit = 'z'
2340 elif is_str and nullable and length:
2341 format_unit = 'z#'
2342
2343 if not format_unit:
2344 fail("str_converter: illegal combination of arguments")
2345 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002346
2347
2348class PyBytesObject_converter(CConverter):
2349 type = 'PyBytesObject *'
2350 format_unit = 'S'
2351
2352class PyByteArrayObject_converter(CConverter):
2353 type = 'PyByteArrayObject *'
2354 format_unit = 'Y'
2355
2356class unicode_converter(CConverter):
2357 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002358 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002359 format_unit = 'U'
2360
Larry Hastingsebdcb502013-11-23 14:54:00 -08002361@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002362@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002363@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002364class Py_UNICODE_converter(CConverter):
2365 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002366 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002367 format_unit = 'u'
2368
Larry Hastingsebdcb502013-11-23 14:54:00 -08002369 def converter_init(self, *, nullable=False, length=False):
2370 format_unit = 'Z' if nullable else 'u'
2371 if length:
2372 format_unit += '#'
2373 self.length = True
2374 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002375
Larry Hastingsebdcb502013-11-23 14:54:00 -08002376#
2377# We define three string conventions for buffer types in the 'types' argument:
2378# 'buffer' : any object supporting the buffer interface
2379# 'rwbuffer': any object supporting the buffer interface, but must be writeable
2380# 'robuffer': any object supporting the buffer interface, but must not be writeable
2381#
2382@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
2383@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
2384@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07002385class Py_buffer_converter(CConverter):
2386 type = 'Py_buffer'
2387 format_unit = 'y*'
2388 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002389 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002390
Larry Hastingsebdcb502013-11-23 14:54:00 -08002391 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002392 if self.default not in (unspecified, None):
2393 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08002394 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002395 types = set(types.strip().split())
2396 bytes_type = set(('bytes',))
2397 bytearray_type = set(('bytearray',))
2398 buffer_type = set(('buffer',))
2399 rwbuffer_type = set(('rwbuffer',))
2400 robuffer_type = set(('robuffer',))
2401 str_type = set(('str',))
2402 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
2403
2404 format_unit = None
2405 if types == (str_type | bytes_bytearray_buffer_type):
2406 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07002407 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002408 if nullable:
2409 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
2410 elif types == (bytes_bytearray_buffer_type):
2411 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002412 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002413 format_unit = 'w*'
2414 if not format_unit:
2415 fail("Py_buffer_converter: illegal combination of arguments")
2416
2417 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002418
2419 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002420 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002421 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002422
2423
2424class self_converter(CConverter):
2425 """
2426 A special-case converter:
2427 this is the default converter used for "self".
2428 """
2429 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08002430 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002431 f = self.function
Larry Hastings8666e652014-01-12 14:12:59 -08002432 if f.kind in (CALLABLE, METHOD_INIT):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002433 if f.cls:
2434 self.name = "self"
2435 else:
2436 self.name = "module"
2437 self.type = "PyModuleDef *"
2438 elif f.kind == STATIC_METHOD:
2439 self.name = "null"
2440 self.type = "void *"
2441 elif f.kind == CLASS_METHOD:
2442 self.name = "cls"
2443 self.type = "PyTypeObject *"
Larry Hastings8666e652014-01-12 14:12:59 -08002444 elif f.kind == METHOD_NEW:
2445 self.name = "type"
2446 self.type = "PyTypeObject *"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002447
Larry Hastings78cf85c2014-01-04 12:44:57 -08002448 if type:
2449 self.type = type
2450
Larry Hastingsebdcb502013-11-23 14:54:00 -08002451 def render(self, parameter, data):
2452 fail("render() should never be called on self_converter instances")
2453
Larry Hastings31826802013-10-19 00:09:25 -07002454
2455
2456def add_c_return_converter(f, name=None):
2457 if not name:
2458 name = f.__name__
2459 if not name.endswith('_return_converter'):
2460 return f
2461 name = name[:-len('_return_converter')]
2462 return_converters[name] = f
2463 return f
2464
2465
2466class CReturnConverterAutoRegister(type):
2467 def __init__(cls, name, bases, classdict):
2468 add_c_return_converter(cls)
2469
2470class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2471
Larry Hastings78cf85c2014-01-04 12:44:57 -08002472 # The C type to use for this variable.
2473 # 'type' should be a Python string specifying the type, e.g. "int".
2474 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002475 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002476
2477 # The Python default value for this parameter, as a Python value.
2478 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002479 default = None
2480
Larry Hastings2a727912014-01-16 11:32:01 -08002481 def __init__(self, *, py_default=None, **kwargs):
2482 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002483 try:
2484 self.return_converter_init(**kwargs)
2485 except TypeError as e:
2486 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2487 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2488
2489 def return_converter_init(self):
2490 pass
2491
2492 def declare(self, data, name="_return_value"):
2493 line = []
2494 add = line.append
2495 add(self.type)
2496 if not self.type.endswith('*'):
2497 add(' ')
2498 add(name + ';')
2499 data.declarations.append(''.join(line))
2500 data.return_value = name
2501
2502 def err_occurred_if(self, expr, data):
2503 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2504
2505 def err_occurred_if_null_pointer(self, variable, data):
2506 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2507
2508 def render(self, function, data):
2509 """
2510 function is a clinic.Function instance.
2511 data is a CRenderData instance.
2512 """
2513 pass
2514
2515add_c_return_converter(CReturnConverter, 'object')
2516
Larry Hastings78cf85c2014-01-04 12:44:57 -08002517class NoneType_return_converter(CReturnConverter):
2518 def render(self, function, data):
2519 self.declare(data)
2520 data.return_conversion.append('''
2521if (_return_value != Py_None)
2522 goto exit;
2523return_value = Py_None;
2524Py_INCREF(Py_None);
2525'''.strip())
2526
Larry Hastings4a55fc52014-01-12 11:09:57 -08002527class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002528 type = 'int'
2529
2530 def render(self, function, data):
2531 self.declare(data)
2532 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002533 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002534
2535class long_return_converter(CReturnConverter):
2536 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002537 conversion_fn = 'PyLong_FromLong'
2538 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002539
2540 def render(self, function, data):
2541 self.declare(data)
2542 self.err_occurred_if("_return_value == -1", data)
2543 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002544 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002545
Larry Hastings4a55fc52014-01-12 11:09:57 -08002546class int_return_converter(long_return_converter):
2547 type = 'int'
2548 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002549
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002550class init_return_converter(long_return_converter):
2551 """
2552 Special return converter for __init__ functions.
2553 """
2554 type = 'int'
2555 cast = '(long)'
2556
2557 def render(self, function, data):
2558 pass
2559
Larry Hastings4a55fc52014-01-12 11:09:57 -08002560class unsigned_long_return_converter(long_return_converter):
2561 type = 'unsigned long'
2562 conversion_fn = 'PyLong_FromUnsignedLong'
2563
2564class unsigned_int_return_converter(unsigned_long_return_converter):
2565 type = 'unsigned int'
2566 cast = '(unsigned long)'
2567
2568class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002569 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002570 conversion_fn = 'PyLong_FromSsize_t'
2571
2572class size_t_return_converter(long_return_converter):
2573 type = 'size_t'
2574 conversion_fn = 'PyLong_FromSize_t'
2575
2576
2577class double_return_converter(CReturnConverter):
2578 type = 'double'
2579 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002580
2581 def render(self, function, data):
2582 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002583 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002584 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002585 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2586
2587class float_return_converter(double_return_converter):
2588 type = 'float'
2589 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002590
2591
2592class DecodeFSDefault_return_converter(CReturnConverter):
2593 type = 'char *'
2594
2595 def render(self, function, data):
2596 self.declare(data)
2597 self.err_occurred_if_null_pointer("_return_value", data)
2598 data.return_conversion.append(
2599 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2600
2601
2602class IndentStack:
2603 def __init__(self):
2604 self.indents = []
2605 self.margin = None
2606
2607 def _ensure(self):
2608 if not self.indents:
2609 fail('IndentStack expected indents, but none are defined.')
2610
2611 def measure(self, line):
2612 """
2613 Returns the length of the line's margin.
2614 """
2615 if '\t' in line:
2616 fail('Tab characters are illegal in the Clinic DSL.')
2617 stripped = line.lstrip()
2618 if not len(stripped):
2619 # we can't tell anything from an empty line
2620 # so just pretend it's indented like our current indent
2621 self._ensure()
2622 return self.indents[-1]
2623 return len(line) - len(stripped)
2624
2625 def infer(self, line):
2626 """
2627 Infer what is now the current margin based on this line.
2628 Returns:
2629 1 if we have indented (or this is the first margin)
2630 0 if the margin has not changed
2631 -N if we have dedented N times
2632 """
2633 indent = self.measure(line)
2634 margin = ' ' * indent
2635 if not self.indents:
2636 self.indents.append(indent)
2637 self.margin = margin
2638 return 1
2639 current = self.indents[-1]
2640 if indent == current:
2641 return 0
2642 if indent > current:
2643 self.indents.append(indent)
2644 self.margin = margin
2645 return 1
2646 # indent < current
2647 if indent not in self.indents:
2648 fail("Illegal outdent.")
2649 outdent_count = 0
2650 while indent != current:
2651 self.indents.pop()
2652 current = self.indents[-1]
2653 outdent_count -= 1
2654 self.margin = margin
2655 return outdent_count
2656
2657 @property
2658 def depth(self):
2659 """
2660 Returns how many margins are currently defined.
2661 """
2662 return len(self.indents)
2663
2664 def indent(self, line):
2665 """
2666 Indents a line by the currently defined margin.
2667 """
2668 return self.margin + line
2669
2670 def dedent(self, line):
2671 """
2672 Dedents a line by the currently defined margin.
2673 (The inverse of 'indent'.)
2674 """
2675 margin = self.margin
2676 indent = self.indents[-1]
2677 if not line.startswith(margin):
2678 fail('Cannot dedent, line does not start with the previous margin:')
2679 return line[indent:]
2680
2681
2682class DSLParser:
2683 def __init__(self, clinic):
2684 self.clinic = clinic
2685
2686 self.directives = {}
2687 for name in dir(self):
2688 # functions that start with directive_ are added to directives
2689 _, s, key = name.partition("directive_")
2690 if s:
2691 self.directives[key] = getattr(self, name)
2692
2693 # functions that start with at_ are too, with an @ in front
2694 _, s, key = name.partition("at_")
2695 if s:
2696 self.directives['@' + key] = getattr(self, name)
2697
2698 self.reset()
2699
2700 def reset(self):
2701 self.function = None
2702 self.state = self.state_dsl_start
2703 self.parameter_indent = None
2704 self.keyword_only = False
2705 self.group = 0
2706 self.parameter_state = self.ps_start
2707 self.indent = IndentStack()
2708 self.kind = CALLABLE
2709 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08002710 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08002711 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07002712
Larry Hastingsebdcb502013-11-23 14:54:00 -08002713 def directive_version(self, required):
2714 global version
2715 if version_comparitor(version, required) < 0:
2716 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2717
Larry Hastings31826802013-10-19 00:09:25 -07002718 def directive_module(self, name):
2719 fields = name.split('.')
2720 new = fields.pop()
2721 module, cls = self.clinic._module_and_class(fields)
2722 if cls:
2723 fail("Can't nest a module inside a class!")
2724 m = Module(name, module)
2725 module.modules[name] = m
2726 self.block.signatures.append(m)
2727
2728 def directive_class(self, name):
2729 fields = name.split('.')
2730 in_classes = False
2731 parent = self
2732 name = fields.pop()
2733 so_far = []
2734 module, cls = self.clinic._module_and_class(fields)
2735
Larry Hastings31826802013-10-19 00:09:25 -07002736 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002737 if cls:
2738 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002739 else:
2740 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002741 self.block.signatures.append(c)
2742
Larry Hastingsbebf7352014-01-17 17:47:17 -08002743 def directive_set(self, name, value):
2744 if name not in ("line_prefix", "line_suffix"):
2745 fail("unknown variable", repr(name))
2746
2747 value = value.format_map({
2748 'block comment start': '/*',
2749 'block comment end': '*/',
2750 })
2751
2752 self.clinic.__dict__[name] = value
2753
2754 def directive_destination(self, name, command, *args):
2755 if command is 'new':
2756 self.clinic.add_destination(name, command, *args)
2757 return
2758
2759 if command is 'clear':
2760 self.clinic.get_destination(name).clear()
2761 fail("unknown destination command", repr(command))
2762
2763
2764 def directive_output(self, field, destination=''):
2765 fd = self.clinic.field_destinations
2766
2767 if field == "preset":
2768 preset = self.clinic.presets.get(destination)
2769 if not preset:
2770 fail("Unknown preset " + repr(destination) + "!")
2771 fd.update(preset)
2772 return
2773
2774 if field == "push":
2775 self.clinic.field_destinations_stack.append(fd.copy())
2776 return
2777
2778 if field == "pop":
2779 if not self.clinic.field_destinations_stack:
2780 fail("Can't 'output pop', stack is empty!")
2781 previous_fd = self.clinic.field_destinations_stack.pop()
2782 fd.update(previous_fd)
2783 return
2784
2785 # secret command for debugging!
2786 if field == "print":
2787 self.block.output.append(pprint.pformat(fd))
2788 self.block.output.append('\n')
2789 return
2790
2791 d = self.clinic.get_destination(destination)
2792
2793 if field == "everything":
2794 for name in list(fd):
2795 fd[name] = d
2796 return
2797
2798 if field not in fd:
2799 fail("Invalid field " + repr(field) + ", must be one of:\n " + ", ".join(valid_fields))
2800 fd[field] = d
2801
2802 def directive_dump(self, name):
2803 self.block.output.append(self.clinic.get_destination(name).dump())
2804
2805 def directive_print(self, *args):
2806 self.block.output.append(' '.join(args))
2807 self.block.output.append('\n')
2808
2809 def directive_preserve(self):
2810 if self.preserve_output:
2811 fail("Can't have preserve twice in one block!")
2812 self.preserve_output = True
2813
Larry Hastings31826802013-10-19 00:09:25 -07002814 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002815 if self.kind is not CALLABLE:
2816 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002817 self.kind = CLASS_METHOD
2818
2819 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002820 if self.kind is not CALLABLE:
2821 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002822 self.kind = STATIC_METHOD
2823
2824 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002825 if self.coexist:
2826 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07002827 self.coexist = True
2828
2829 def parse(self, block):
2830 self.reset()
2831 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08002832 self.saved_output = self.block.output
2833 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07002834 block_start = self.clinic.block_parser.line_number
2835 lines = block.input.split('\n')
2836 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2837 if '\t' in line:
2838 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2839 self.state(line)
2840
2841 self.next(self.state_terminal)
2842 self.state(None)
2843
Larry Hastingsbebf7352014-01-17 17:47:17 -08002844 block.output.extend(self.clinic.language.render(clinic, block.signatures))
2845
2846 if self.preserve_output:
2847 if block.output:
2848 fail("'preserve' only works for blocks that don't produce any output!")
2849 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07002850
2851 @staticmethod
2852 def ignore_line(line):
2853 # ignore comment-only lines
2854 if line.lstrip().startswith('#'):
2855 return True
2856
2857 # Ignore empty lines too
2858 # (but not in docstring sections!)
2859 if not line.strip():
2860 return True
2861
2862 return False
2863
2864 @staticmethod
2865 def calculate_indent(line):
2866 return len(line) - len(line.strip())
2867
2868 def next(self, state, line=None):
2869 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2870 self.state = state
2871 if line is not None:
2872 self.state(line)
2873
2874 def state_dsl_start(self, line):
2875 # self.block = self.ClinicOutputBlock(self)
2876 if self.ignore_line(line):
2877 return
2878 self.next(self.state_modulename_name, line)
2879
2880 def state_modulename_name(self, line):
2881 # looking for declaration, which establishes the leftmost column
2882 # line should be
2883 # modulename.fnname [as c_basename] [-> return annotation]
2884 # square brackets denote optional syntax.
2885 #
Larry Hastings4a714d42014-01-14 22:22:41 -08002886 # alternatively:
2887 # modulename.fnname [as c_basename] = modulename.existing_fn_name
2888 # clones the parameters and return converter from that
2889 # function. you can't modify them. you must enter a
2890 # new docstring.
2891 #
Larry Hastings31826802013-10-19 00:09:25 -07002892 # (but we might find a directive first!)
2893 #
2894 # this line is permitted to start with whitespace.
2895 # we'll call this number of spaces F (for "function").
2896
2897 if not line.strip():
2898 return
2899
2900 self.indent.infer(line)
2901
2902 # is it a directive?
2903 fields = shlex.split(line)
2904 directive_name = fields[0]
2905 directive = self.directives.get(directive_name, None)
2906 if directive:
Larry Hastingsbebf7352014-01-17 17:47:17 -08002907 try:
2908 directive(*fields[1:])
2909 except TypeError as e:
2910 fail(str(e))
Larry Hastings31826802013-10-19 00:09:25 -07002911 return
2912
Larry Hastings4a714d42014-01-14 22:22:41 -08002913 # are we cloning?
2914 before, equals, existing = line.rpartition('=')
2915 if equals:
2916 full_name, _, c_basename = before.partition(' as ')
2917 full_name = full_name.strip()
2918 c_basename = c_basename.strip()
2919 existing = existing.strip()
2920 if (is_legal_py_identifier(full_name) and
2921 (not c_basename or is_legal_c_identifier(c_basename)) and
2922 is_legal_py_identifier(existing)):
2923 # we're cloning!
2924 fields = [x.strip() for x in existing.split('.')]
2925 function_name = fields.pop()
2926 module, cls = self.clinic._module_and_class(fields)
2927
2928 for existing_function in (cls or module).functions:
2929 if existing_function.name == function_name:
2930 break
2931 else:
2932 existing_function = None
2933 if not existing_function:
2934 fail("Couldn't find existing function " + repr(existing) + "!")
2935
2936 fields = [x.strip() for x in full_name.split('.')]
2937 function_name = fields.pop()
2938 module, cls = self.clinic._module_and_class(fields)
2939
2940 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
2941 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
2942 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2943 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
2944
2945 self.function.parameters = existing_function.parameters.copy()
2946
2947 self.block.signatures.append(self.function)
2948 (cls or module).functions.append(self.function)
2949 self.next(self.state_function_docstring)
2950 return
2951
Larry Hastings31826802013-10-19 00:09:25 -07002952 line, _, returns = line.partition('->')
2953
2954 full_name, _, c_basename = line.partition(' as ')
2955 full_name = full_name.strip()
2956 c_basename = c_basename.strip() or None
2957
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002958 if not is_legal_py_identifier(full_name):
2959 fail("Illegal function name: {}".format(full_name))
2960 if c_basename and not is_legal_c_identifier(c_basename):
2961 fail("Illegal C basename: {}".format(c_basename))
2962
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002963 return_converter = None
2964 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07002965 ast_input = "def x() -> {}: pass".format(returns)
2966 module = None
2967 try:
2968 module = ast.parse(ast_input)
2969 except SyntaxError:
2970 pass
2971 if not module:
2972 fail("Badly-formed annotation for " + full_name + ": " + returns)
2973 try:
2974 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002975 if legacy:
2976 fail("Legacy converter {!r} not allowed as a return converter"
2977 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07002978 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002979 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07002980 return_converter = return_converters[name](**kwargs)
2981 except ValueError:
2982 fail("Badly-formed annotation for " + full_name + ": " + returns)
2983
2984 fields = [x.strip() for x in full_name.split('.')]
2985 function_name = fields.pop()
2986 module, cls = self.clinic._module_and_class(fields)
2987
Larry Hastings8666e652014-01-12 14:12:59 -08002988 fields = full_name.split('.')
2989 if fields[-1] == '__new__':
2990 if (self.kind != CLASS_METHOD) or (not cls):
2991 fail("__new__ must be a class method!")
2992 self.kind = METHOD_NEW
2993 elif fields[-1] == '__init__':
2994 if (self.kind != CALLABLE) or (not cls):
2995 fail("__init__ must be a normal method, not a class or static method!")
2996 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002997 if not return_converter:
2998 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08002999 elif fields[-1] in unsupported_special_methods:
3000 fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
3001
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003002 if not return_converter:
3003 return_converter = CReturnConverter()
3004
Larry Hastings31826802013-10-19 00:09:25 -07003005 if not module:
3006 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3007 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3008 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3009 self.block.signatures.append(self.function)
Larry Hastings4a714d42014-01-14 22:22:41 -08003010 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003011 self.next(self.state_parameters_start)
3012
3013 # Now entering the parameters section. The rules, formally stated:
3014 #
3015 # * All lines must be indented with spaces only.
3016 # * The first line must be a parameter declaration.
3017 # * The first line must be indented.
3018 # * This first line establishes the indent for parameters.
3019 # * We'll call this number of spaces P (for "parameter").
3020 # * Thenceforth:
3021 # * Lines indented with P spaces specify a parameter.
3022 # * Lines indented with > P spaces are docstrings for the previous
3023 # parameter.
3024 # * We'll call this number of spaces D (for "docstring").
3025 # * All subsequent lines indented with >= D spaces are stored as
3026 # part of the per-parameter docstring.
3027 # * All lines will have the first D spaces of the indent stripped
3028 # before they are stored.
3029 # * It's illegal to have a line starting with a number of spaces X
3030 # such that P < X < D.
3031 # * A line with < P spaces is the first line of the function
3032 # docstring, which ends processing for parameters and per-parameter
3033 # docstrings.
3034 # * The first line of the function docstring must be at the same
3035 # indent as the function declaration.
3036 # * It's illegal to have any line in the parameters section starting
3037 # with X spaces such that F < X < P. (As before, F is the indent
3038 # of the function declaration.)
3039 #
Larry Hastings31826802013-10-19 00:09:25 -07003040 # Also, currently Argument Clinic places the following restrictions on groups:
3041 # * Each group must contain at least one parameter.
3042 # * Each group may contain at most one group, which must be the furthest
3043 # thing in the group from the required parameters. (The nested group
3044 # must be the first in the group when it's before the required
3045 # parameters, and the last thing in the group when after the required
3046 # parameters.)
3047 # * There may be at most one (top-level) group to the left or right of
3048 # the required parameters.
3049 # * You must specify a slash, and it must be after all parameters.
3050 # (In other words: either all parameters are positional-only,
3051 # or none are.)
3052 #
3053 # Said another way:
3054 # * Each group must contain at least one parameter.
3055 # * All left square brackets before the required parameters must be
3056 # consecutive. (You can't have a left square bracket followed
3057 # by a parameter, then another left square bracket. You can't
3058 # have a left square bracket, a parameter, a right square bracket,
3059 # and then a left square bracket.)
3060 # * All right square brackets after the required parameters must be
3061 # consecutive.
3062 #
3063 # These rules are enforced with a single state variable:
3064 # "parameter_state". (Previously the code was a miasma of ifs and
3065 # separate boolean state variables.) The states are:
3066 #
3067 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
3068 # 01 2 3 4 5 6 <- state transitions
3069 #
3070 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3071 # 1: ps_left_square_before. left square brackets before required parameters.
3072 # 2: ps_group_before. in a group, before required parameters.
3073 # 3: ps_required. required parameters. (renumber left groups!)
3074 # 4: ps_group_after. in a group, after required parameters.
3075 # 5: ps_right_square_after. right square brackets after required parameters.
3076 # 6: ps_seen_slash. seen slash.
3077 ps_start, ps_left_square_before, ps_group_before, ps_required, \
3078 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
3079
3080 def state_parameters_start(self, line):
3081 if self.ignore_line(line):
3082 return
3083
3084 # if this line is not indented, we have no parameters
3085 if not self.indent.infer(line):
3086 return self.next(self.state_function_docstring, line)
3087
Larry Hastings2a727912014-01-16 11:32:01 -08003088 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003089 return self.next(self.state_parameter, line)
3090
3091
3092 def to_required(self):
3093 """
3094 Transition to the "required" parameter state.
3095 """
3096 if self.parameter_state != self.ps_required:
3097 self.parameter_state = self.ps_required
3098 for p in self.function.parameters.values():
3099 p.group = -p.group
3100
3101 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003102 if self.parameter_continuation:
3103 line = self.parameter_continuation + ' ' + line.lstrip()
3104 self.parameter_continuation = ''
3105
Larry Hastings31826802013-10-19 00:09:25 -07003106 if self.ignore_line(line):
3107 return
3108
3109 assert self.indent.depth == 2
3110 indent = self.indent.infer(line)
3111 if indent == -1:
3112 # we outdented, must be to definition column
3113 return self.next(self.state_function_docstring, line)
3114
3115 if indent == 1:
3116 # we indented, must be to new parameter docstring column
3117 return self.next(self.state_parameter_docstring_start, line)
3118
Larry Hastings2a727912014-01-16 11:32:01 -08003119 line = line.rstrip()
3120 if line.endswith('\\'):
3121 self.parameter_continuation = line[:-1]
3122 return
3123
Larry Hastings31826802013-10-19 00:09:25 -07003124 line = line.lstrip()
3125
3126 if line in ('*', '/', '[', ']'):
3127 self.parse_special_symbol(line)
3128 return
3129
3130 if self.parameter_state in (self.ps_start, self.ps_required):
3131 self.to_required()
3132 elif self.parameter_state == self.ps_left_square_before:
3133 self.parameter_state = self.ps_group_before
3134 elif self.parameter_state == self.ps_group_before:
3135 if not self.group:
3136 self.to_required()
3137 elif self.parameter_state == self.ps_group_after:
3138 pass
3139 else:
3140 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3141
Larry Hastings2a727912014-01-16 11:32:01 -08003142 base, equals, default = line.rpartition('=')
3143 if not equals:
3144 base = default
3145 default = None
Larry Hastings31826802013-10-19 00:09:25 -07003146 module = None
3147 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003148 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003149 module = ast.parse(ast_input)
3150 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003151 try:
3152 default = None
3153 ast_input = "def x({}): pass".format(line)
3154 module = ast.parse(ast_input)
3155 except SyntaxError:
3156 pass
Larry Hastings31826802013-10-19 00:09:25 -07003157 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003158 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003159
3160 function_args = module.body[0].args
3161 parameter = function_args.args[0]
3162
Larry Hastings16c51912014-01-07 11:53:01 -08003163 parameter_name = parameter.arg
3164 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3165
Larry Hastings2a727912014-01-16 11:32:01 -08003166 if not default:
3167 value = unspecified
3168 if 'py_default' in kwargs:
3169 fail("You can't specify py_default without specifying a default value!")
3170 else:
3171 default = default.strip()
3172 ast_input = "x = {}".format(default)
3173 try:
3174 module = ast.parse(ast_input)
3175
3176 # blacklist of disallowed ast nodes
3177 class DetectBadNodes(ast.NodeVisitor):
3178 bad = False
3179 def bad_node(self, node):
3180 self.bad = True
3181
3182 # inline function call
3183 visit_Call = bad_node
3184 # inline if statement ("x = 3 if y else z")
3185 visit_IfExp = bad_node
3186
3187 # comprehensions and generator expressions
3188 visit_ListComp = visit_SetComp = bad_node
3189 visit_DictComp = visit_GeneratorExp = bad_node
3190
3191 # literals for advanced types
3192 visit_Dict = visit_Set = bad_node
3193 visit_List = visit_Tuple = bad_node
3194
3195 # "starred": "a = [1, 2, 3]; *a"
3196 visit_Starred = bad_node
3197
3198 # allow ellipsis, for now
3199 # visit_Ellipsis = bad_node
3200
3201 blacklist = DetectBadNodes()
3202 blacklist.visit(module)
3203 if blacklist.bad:
3204 fail("Unsupported expression as default value: " + repr(default))
3205
3206 expr = module.body[0].value
3207 # mild hack: explicitly support NULL as a default value
3208 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3209 value = NULL
3210 py_default = 'None'
3211 c_default = "NULL"
3212 elif (isinstance(expr, ast.BinOp) or
3213 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3214 c_default = kwargs.get("c_default")
3215 if not (isinstance(c_default, str) and c_default):
3216 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3217 py_default = default
3218 value = unknown
3219 elif isinstance(expr, ast.Attribute):
3220 a = []
3221 n = expr
3222 while isinstance(n, ast.Attribute):
3223 a.append(n.attr)
3224 n = n.value
3225 if not isinstance(n, ast.Name):
3226 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3227 a.append(n.id)
3228 py_default = ".".join(reversed(a))
3229
3230 c_default = kwargs.get("c_default")
3231 if not (isinstance(c_default, str) and c_default):
3232 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3233
3234 try:
3235 value = eval(py_default)
3236 except NameError:
3237 value = unknown
3238 else:
3239 value = ast.literal_eval(expr)
3240 py_default = repr(value)
3241 if isinstance(value, (bool, None.__class__)):
3242 c_default = "Py_" + py_default
3243 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003244 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003245 else:
3246 c_default = py_default
3247
3248 except SyntaxError as e:
3249 fail("Syntax error: " + repr(e.text))
3250 except (ValueError, AttributeError):
3251 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003252 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003253 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003254 if not (isinstance(c_default, str) and c_default):
3255 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3256
Larry Hastings2a727912014-01-16 11:32:01 -08003257 kwargs.setdefault('c_default', c_default)
3258 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003259
Larry Hastings31826802013-10-19 00:09:25 -07003260 dict = legacy_converters if legacy else converters
3261 legacy_str = "legacy " if legacy else ""
3262 if name not in dict:
3263 fail('{} is not a valid {}converter'.format(name, legacy_str))
3264 converter = dict[name](parameter_name, self.function, value, **kwargs)
3265
Larry Hastingsebdcb502013-11-23 14:54:00 -08003266 # special case: if it's the self converter,
3267 # don't actually add it to the parameter list
3268 if isinstance(converter, self_converter):
3269 if self.function.parameters or (self.parameter_state != self.ps_required):
3270 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
3271 if self.function.self_converter:
3272 fail("You can't specify the 'self' parameter more than once.")
3273 self.function.self_converter = converter
3274 self.parameter_state = self.ps_start
3275 return
3276
Larry Hastings31826802013-10-19 00:09:25 -07003277 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
3278 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003279
3280 if parameter_name in self.function.parameters:
3281 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003282 self.function.parameters[parameter_name] = p
3283
3284 def parse_converter(self, annotation):
3285 if isinstance(annotation, ast.Str):
3286 return annotation.s, True, {}
3287
3288 if isinstance(annotation, ast.Name):
3289 return annotation.id, False, {}
3290
Larry Hastings4a55fc52014-01-12 11:09:57 -08003291 if not isinstance(annotation, ast.Call):
3292 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003293
3294 name = annotation.func.id
3295 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
3296 return name, False, kwargs
3297
3298 def parse_special_symbol(self, symbol):
3299 if self.parameter_state == self.ps_seen_slash:
3300 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
3301
3302 if symbol == '*':
3303 if self.keyword_only:
3304 fail("Function " + self.function.name + " uses '*' more than once.")
3305 self.keyword_only = True
3306 elif symbol == '[':
3307 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3308 self.parameter_state = self.ps_left_square_before
3309 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3310 self.parameter_state = self.ps_group_after
3311 else:
3312 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3313 self.group += 1
3314 elif symbol == ']':
3315 if not self.group:
3316 fail("Function " + self.function.name + " has a ] without a matching [.")
3317 if not any(p.group == self.group for p in self.function.parameters.values()):
3318 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3319 self.group -= 1
3320 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3321 self.parameter_state = self.ps_group_before
3322 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3323 self.parameter_state = self.ps_right_square_after
3324 else:
3325 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3326 elif symbol == '/':
3327 # ps_required is allowed here, that allows positional-only without option groups
3328 # to work (and have default values!)
3329 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
3330 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3331 if self.keyword_only:
3332 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3333 self.parameter_state = self.ps_seen_slash
3334 # fixup preceeding parameters
3335 for p in self.function.parameters.values():
3336 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
3337 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3338 p.kind = inspect.Parameter.POSITIONAL_ONLY
3339
3340 def state_parameter_docstring_start(self, line):
3341 self.parameter_docstring_indent = len(self.indent.margin)
3342 assert self.indent.depth == 3
3343 return self.next(self.state_parameter_docstring, line)
3344
3345 # every line of the docstring must start with at least F spaces,
3346 # where F > P.
3347 # these F spaces will be stripped.
3348 def state_parameter_docstring(self, line):
3349 stripped = line.strip()
3350 if stripped.startswith('#'):
3351 return
3352
3353 indent = self.indent.measure(line)
3354 if indent < self.parameter_docstring_indent:
3355 self.indent.infer(line)
3356 assert self.indent.depth < 3
3357 if self.indent.depth == 2:
3358 # back to a parameter
3359 return self.next(self.state_parameter, line)
3360 assert self.indent.depth == 1
3361 return self.next(self.state_function_docstring, line)
3362
3363 assert self.function.parameters
3364 last_parameter = next(reversed(list(self.function.parameters.values())))
3365
3366 new_docstring = last_parameter.docstring
3367
3368 if new_docstring:
3369 new_docstring += '\n'
3370 if stripped:
3371 new_docstring += self.indent.dedent(line)
3372
3373 last_parameter.docstring = new_docstring
3374
3375 # the final stanza of the DSL is the docstring.
3376 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003377 if self.group:
3378 fail("Function " + self.function.name + " has a ] without a matching [.")
3379
3380 stripped = line.strip()
3381 if stripped.startswith('#'):
3382 return
3383
3384 new_docstring = self.function.docstring
3385 if new_docstring:
3386 new_docstring += "\n"
3387 if stripped:
3388 line = self.indent.dedent(line).rstrip()
3389 else:
3390 line = ''
3391 new_docstring += line
3392 self.function.docstring = new_docstring
3393
3394 def format_docstring(self):
3395 f = self.function
3396
3397 add, output = text_accumulator()
3398 parameters = list(f.parameters.values())
3399
3400 ##
3401 ## docstring first line
3402 ##
3403
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003404 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07003405 add('(')
3406
3407 # populate "right_bracket_count" field for every parameter
3408 if parameters:
3409 # for now, the only way Clinic supports positional-only parameters
3410 # is if all of them are positional-only.
3411 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
3412 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
3413 assert all(positional_only_parameters)
3414 for p in parameters:
3415 p.right_bracket_count = abs(p.group)
3416 else:
3417 # don't put any right brackets around non-positional-only parameters, ever.
3418 for p in parameters:
3419 p.right_bracket_count = 0
3420
3421 right_bracket_count = 0
3422
3423 def fix_right_bracket_count(desired):
3424 nonlocal right_bracket_count
3425 s = ''
3426 while right_bracket_count < desired:
3427 s += '['
3428 right_bracket_count += 1
3429 while right_bracket_count > desired:
3430 s += ']'
3431 right_bracket_count -= 1
3432 return s
3433
3434 added_star = False
3435 add_comma = False
3436
3437 for p in parameters:
3438 assert p.name
3439
3440 if p.is_keyword_only() and not added_star:
3441 added_star = True
3442 if add_comma:
3443 add(', ')
3444 add('*')
3445
3446 a = [p.name]
3447 if p.converter.is_optional():
3448 a.append('=')
3449 value = p.converter.default
Larry Hastings2a727912014-01-16 11:32:01 -08003450 a.append(p.converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003451 s = fix_right_bracket_count(p.right_bracket_count)
3452 s += "".join(a)
3453 if add_comma:
3454 add(', ')
3455 add(s)
3456 add_comma = True
3457
3458 add(fix_right_bracket_count(0))
3459 add(')')
3460
Larry Hastings2a727912014-01-16 11:32:01 -08003461 # PEP 8 says:
3462 #
3463 # The Python standard library will not use function annotations
3464 # as that would result in a premature commitment to a particular
3465 # annotation style. Instead, the annotations are left for users
3466 # to discover and experiment with useful annotation styles.
3467 #
3468 # therefore this is commented out:
3469 #
3470 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003471 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08003472 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003473
3474 docstring_first_line = output()
3475
3476 # now fix up the places where the brackets look wrong
3477 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
3478
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003479 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07003480 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003481 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07003482 for p in parameters:
3483 if not p.docstring.strip():
3484 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003485 if spacer_line:
3486 add('\n')
3487 else:
3488 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07003489 add(" ")
3490 add(p.name)
3491 add('\n')
3492 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003493 parameters = output()
3494 if parameters:
3495 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07003496
3497 ##
3498 ## docstring body
3499 ##
3500
3501 docstring = f.docstring.rstrip()
3502 lines = [line.rstrip() for line in docstring.split('\n')]
3503
3504 # Enforce the summary line!
3505 # The first line of a docstring should be a summary of the function.
3506 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
3507 # by itself.
3508 #
3509 # Argument Clinic enforces the following rule:
3510 # * either the docstring is empty,
3511 # * or it must have a summary line.
3512 #
3513 # Guido said Clinic should enforce this:
3514 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
3515
3516 if len(lines) >= 2:
3517 if lines[1]:
3518 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
3519 "Every non-blank function docstring must start with\n" +
3520 "a single line summary followed by an empty line.")
3521 elif len(lines) == 1:
3522 # the docstring is only one line right now--the summary line.
3523 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003524 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07003525 lines.append('')
3526
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003527 parameters_marker_count = len(docstring.split('{parameters}')) - 1
3528 if parameters_marker_count > 1:
3529 fail('You may not specify {parameters} more than once in a docstring!')
3530
3531 if not parameters_marker_count:
3532 # insert after summary line
3533 lines.insert(2, '{parameters}')
3534
3535 # insert at front of docstring
3536 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07003537
3538 docstring = "\n".join(lines)
3539
3540 add(docstring)
3541 docstring = output()
3542
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003543 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07003544 docstring = docstring.rstrip()
3545
3546 return docstring
3547
3548 def state_terminal(self, line):
3549 """
3550 Called when processing the block is done.
3551 """
3552 assert not line
3553
3554 if not self.function:
3555 return
3556
Larry Hastings6d2ea212014-01-05 02:50:45 -08003557 if not self.function.self_converter:
3558 self.function.self_converter = self_converter("self", self.function)
3559
Larry Hastings31826802013-10-19 00:09:25 -07003560 if self.keyword_only:
3561 values = self.function.parameters.values()
3562 if not values:
3563 no_parameter_after_star = True
3564 else:
3565 last_parameter = next(reversed(list(values)))
3566 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
3567 if no_parameter_after_star:
3568 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
3569
3570 # remove trailing whitespace from all parameter docstrings
3571 for name, value in self.function.parameters.items():
3572 if not value:
3573 continue
3574 value.docstring = value.docstring.rstrip()
3575
3576 self.function.docstring = self.format_docstring()
3577
3578
3579# maps strings to callables.
3580# the callable should return an object
3581# that implements the clinic parser
3582# interface (__init__ and parse).
3583#
3584# example parsers:
3585# "clinic", handles the Clinic DSL
3586# "python", handles running Python code
3587#
3588parsers = {'clinic' : DSLParser, 'python': PythonParser}
3589
3590
3591clinic = None
3592
3593
3594def main(argv):
3595 import sys
3596
3597 if sys.version_info.major < 3 or sys.version_info.minor < 3:
3598 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
3599
3600 import argparse
3601 cmdline = argparse.ArgumentParser()
3602 cmdline.add_argument("-f", "--force", action='store_true')
3603 cmdline.add_argument("-o", "--output", type=str)
3604 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003605 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07003606 cmdline.add_argument("filename", type=str, nargs="*")
3607 ns = cmdline.parse_args(argv)
3608
3609 if ns.converters:
3610 if ns.filename:
3611 print("Usage error: can't specify --converters and a filename at the same time.")
3612 print()
3613 cmdline.print_usage()
3614 sys.exit(-1)
3615 converters = []
3616 return_converters = []
3617 ignored = set("""
3618 add_c_converter
3619 add_c_return_converter
3620 add_default_legacy_c_converter
3621 add_legacy_c_converter
3622 """.strip().split())
3623 module = globals()
3624 for name in module:
3625 for suffix, ids in (
3626 ("_return_converter", return_converters),
3627 ("_converter", converters),
3628 ):
3629 if name in ignored:
3630 continue
3631 if name.endswith(suffix):
3632 ids.append((name, name[:-len(suffix)]))
3633 break
3634 print()
3635
3636 print("Legacy converters:")
3637 legacy = sorted(legacy_converters)
3638 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
3639 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
3640 print()
3641
3642 for title, attribute, ids in (
3643 ("Converters", 'converter_init', converters),
3644 ("Return converters", 'return_converter_init', return_converters),
3645 ):
3646 print(title + ":")
3647 longest = -1
3648 for name, short_name in ids:
3649 longest = max(longest, len(short_name))
3650 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
3651 cls = module[name]
3652 callable = getattr(cls, attribute, None)
3653 if not callable:
3654 continue
3655 signature = inspect.signature(callable)
3656 parameters = []
3657 for parameter_name, parameter in signature.parameters.items():
3658 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
3659 if parameter.default != inspect.Parameter.empty:
3660 s = '{}={!r}'.format(parameter_name, parameter.default)
3661 else:
3662 s = parameter_name
3663 parameters.append(s)
3664 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07003665 print()
Larry Hastings2a727912014-01-16 11:32:01 -08003666 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
3667 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07003668 sys.exit(0)
3669
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003670 if ns.make:
3671 if ns.output or ns.filename:
3672 print("Usage error: can't use -o or filenames with --make.")
3673 print()
3674 cmdline.print_usage()
3675 sys.exit(-1)
3676 for root, dirs, files in os.walk('.'):
3677 for rcs_dir in ('.svn', '.git', '.hg'):
3678 if rcs_dir in dirs:
3679 dirs.remove(rcs_dir)
3680 for filename in files:
3681 if not filename.endswith('.c'):
3682 continue
3683 path = os.path.join(root, filename)
3684 parse_file(path, verify=not ns.force)
3685 return
3686
Larry Hastings31826802013-10-19 00:09:25 -07003687 if not ns.filename:
3688 cmdline.print_usage()
3689 sys.exit(-1)
3690
3691 if ns.output and len(ns.filename) > 1:
3692 print("Usage error: can't use -o with multiple filenames.")
3693 print()
3694 cmdline.print_usage()
3695 sys.exit(-1)
3696
3697 for filename in ns.filename:
3698 parse_file(filename, output=ns.output, verify=not ns.force)
3699
3700
3701if __name__ == "__main__":
3702 sys.exit(main(sys.argv[1:]))