blob: 5480add7baa717d2b16b8afc61bd406b0b01b115 [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
11import clinic
12import collections
13import contextlib
14import functools
15import hashlib
16import inspect
17import io
18import itertools
19import os
20import re
21import shlex
22import sys
23import tempfile
24import textwrap
25
Larry Hastings31826802013-10-19 00:09:25 -070026# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070027#
28# soon:
29#
30# * allow mixing any two of {positional-only, positional-or-keyword,
31# keyword-only}
32# * dict constructor uses positional-only and keyword-only
33# * max and min use positional only with an optional group
34# and keyword-only
35#
Larry Hastings31826802013-10-19 00:09:25 -070036
Larry Hastingsebdcb502013-11-23 14:54:00 -080037version = '1'
38
Larry Hastings31826802013-10-19 00:09:25 -070039_empty = inspect._empty
40_void = inspect._void
41
42
43class Unspecified:
44 def __repr__(self):
45 return '<Unspecified>'
46
47unspecified = Unspecified()
48
49
50class Null:
51 def __repr__(self):
52 return '<Null>'
53
54NULL = Null()
55
56
57def _text_accumulator():
58 text = []
59 def output():
60 s = ''.join(text)
61 text.clear()
62 return s
63 return text, text.append, output
64
65
66def text_accumulator():
67 """
68 Creates a simple text accumulator / joiner.
69
70 Returns a pair of callables:
71 append, output
72 "append" appends a string to the accumulator.
73 "output" returns the contents of the accumulator
74 joined together (''.join(accumulator)) and
75 empties the accumulator.
76 """
77 text, append, output = _text_accumulator()
78 return append, output
79
80
81def fail(*args, filename=None, line_number=None):
82 joined = " ".join([str(a) for a in args])
83 add, output = text_accumulator()
84 add("Error")
85 if clinic:
86 if filename is None:
87 filename = clinic.filename
88 if clinic.block_parser and (line_number is None):
89 line_number = clinic.block_parser.line_number
90 if filename is not None:
91 add(' in file "' + filename + '"')
92 if line_number is not None:
93 add(" on line " + str(line_number))
94 add(':\n')
95 add(joined)
96 print(output())
97 sys.exit(-1)
98
99
100
101def quoted_for_c_string(s):
102 for old, new in (
103 ('"', '\\"'),
104 ("'", "\\'"),
105 ):
106 s = s.replace(old, new)
107 return s
108
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700109is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
110
111def is_legal_py_identifier(s):
112 return all(is_legal_c_identifier(field) for field in s.split('.'))
113
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800114# added "module", "self", "cls", and "null" just to be safe
Larry Hastings31826802013-10-19 00:09:25 -0700115# (clinic will generate variables with these names)
116c_keywords = set("""
117asm auto break case char cls const continue default do double
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800118else enum extern float for goto if inline int long module null
119register return self short signed sizeof static struct switch
120typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700121""".strip().split())
122
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700123def ensure_legal_c_identifier(s):
124 # for now, just complain if what we're given isn't legal
125 if not is_legal_c_identifier(s):
126 fail("Illegal C identifier: {}".format(s))
127 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700128 if s in c_keywords:
129 return s + "_value"
130 return s
131
132def rstrip_lines(s):
133 text, add, output = _text_accumulator()
134 for line in s.split('\n'):
135 add(line.rstrip())
136 add('\n')
137 text.pop()
138 return output()
139
140def linear_format(s, **kwargs):
141 """
142 Perform str.format-like substitution, except:
143 * The strings substituted must be on lines by
144 themselves. (This line is the "source line".)
145 * If the substitution text is empty, the source line
146 is removed in the output.
147 * If the substitution text is not empty:
148 * Each line of the substituted text is indented
149 by the indent of the source line.
150 * A newline will be added to the end.
151 """
152
153 add, output = text_accumulator()
154 for line in s.split('\n'):
155 indent, curly, trailing = line.partition('{')
156 if not curly:
157 add(line)
158 add('\n')
159 continue
160
161 name, curl, trailing = trailing.partition('}')
162 if not curly or name not in kwargs:
163 add(line)
164 add('\n')
165 continue
166
167 if trailing:
168 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
169 if indent.strip():
170 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
171
172 value = kwargs[name]
173 if not value:
174 continue
175
176 value = textwrap.indent(rstrip_lines(value), indent)
177 add(value)
178 add('\n')
179
180 return output()[:-1]
181
Larry Hastingsebdcb502013-11-23 14:54:00 -0800182def version_splitter(s):
183 """Splits a version string into a tuple of integers.
184
185 The following ASCII characters are allowed, and employ
186 the following conversions:
187 a -> -3
188 b -> -2
189 c -> -1
190 (This permits Python-style version strings such as "1.4b3".)
191 """
192 version = []
193 accumulator = []
194 def flush():
195 if not accumulator:
196 raise ValueError('Malformed version string: ' + repr(s))
197 version.append(int(''.join(accumulator)))
198 accumulator.clear()
199
200 for c in s:
201 if c.isdigit():
202 accumulator.append(c)
203 elif c == '.':
204 flush()
205 elif c in 'abc':
206 flush()
207 version.append('abc'.index(c) - 3)
208 else:
209 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
210 flush()
211 return tuple(version)
212
213def version_comparitor(version1, version2):
214 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
215 for i, (a, b) in enumerate(iterator):
216 if a < b:
217 return -1
218 if a > b:
219 return 1
220 return 0
221
Larry Hastings31826802013-10-19 00:09:25 -0700222
223class CRenderData:
224 def __init__(self):
225
226 # The C statements to declare variables.
227 # Should be full lines with \n eol characters.
228 self.declarations = []
229
230 # The C statements required to initialize the variables before the parse call.
231 # Should be full lines with \n eol characters.
232 self.initializers = []
233
234 # The entries for the "keywords" array for PyArg_ParseTuple.
235 # Should be individual strings representing the names.
236 self.keywords = []
237
238 # The "format units" for PyArg_ParseTuple.
239 # Should be individual strings that will get
240 self.format_units = []
241
242 # The varargs arguments for PyArg_ParseTuple.
243 self.parse_arguments = []
244
245 # The parameter declarations for the impl function.
246 self.impl_parameters = []
247
248 # The arguments to the impl function at the time it's called.
249 self.impl_arguments = []
250
251 # For return converters: the name of the variable that
252 # should receive the value returned by the impl.
253 self.return_value = "return_value"
254
255 # For return converters: the code to convert the return
256 # value from the parse function. This is also where
257 # you should check the _return_value for errors, and
258 # "goto exit" if there are any.
259 self.return_conversion = []
260
261 # The C statements required to clean up after the impl call.
262 self.cleanup = []
263
264
265class Language(metaclass=abc.ABCMeta):
266
267 start_line = ""
268 body_prefix = ""
269 stop_line = ""
270 checksum_line = ""
271
272 @abc.abstractmethod
273 def render(self, block):
274 pass
275
276 def validate(self):
277 def assert_only_one(field, token='dsl_name'):
278 line = getattr(self, field)
279 token = '{' + token + '}'
280 if len(line.split(token)) != 2:
281 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
282 assert_only_one('start_line')
283 assert_only_one('stop_line')
284 assert_only_one('checksum_line')
285 assert_only_one('checksum_line', 'checksum')
286
287 if len(self.body_prefix.split('{dsl_name}')) >= 3:
288 fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
289
290
291
292class PythonLanguage(Language):
293
294 language = 'Python'
295 start_line = "#/*[{dsl_name}]"
296 body_prefix = "#"
297 stop_line = "#[{dsl_name}]*/"
298 checksum_line = "#/*[{dsl_name} checksum: {checksum}]*/"
299
300
301def permute_left_option_groups(l):
302 """
303 Given [1, 2, 3], should yield:
304 ()
305 (3,)
306 (2, 3)
307 (1, 2, 3)
308 """
309 yield tuple()
310 accumulator = []
311 for group in reversed(l):
312 accumulator = list(group) + accumulator
313 yield tuple(accumulator)
314
315
316def permute_right_option_groups(l):
317 """
318 Given [1, 2, 3], should yield:
319 ()
320 (1,)
321 (1, 2)
322 (1, 2, 3)
323 """
324 yield tuple()
325 accumulator = []
326 for group in l:
327 accumulator.extend(group)
328 yield tuple(accumulator)
329
330
331def permute_optional_groups(left, required, right):
332 """
333 Generator function that computes the set of acceptable
334 argument lists for the provided iterables of
335 argument groups. (Actually it generates a tuple of tuples.)
336
337 Algorithm: prefer left options over right options.
338
339 If required is empty, left must also be empty.
340 """
341 required = tuple(required)
342 result = []
343
344 if not required:
345 assert not left
346
347 accumulator = []
348 counts = set()
349 for r in permute_right_option_groups(right):
350 for l in permute_left_option_groups(left):
351 t = l + required + r
352 if len(t) in counts:
353 continue
354 counts.add(len(t))
355 accumulator.append(t)
356
357 accumulator.sort(key=len)
358 return tuple(accumulator)
359
360
361class CLanguage(Language):
362
363 language = 'C'
364 start_line = "/*[{dsl_name}]"
365 body_prefix = ""
366 stop_line = "[{dsl_name}]*/"
367 checksum_line = "/*[{dsl_name} checksum: {checksum}]*/"
368
369 def render(self, signatures):
370 function = None
371 for o in signatures:
372 if isinstance(o, Function):
373 if function:
374 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
375 function = o
376 return self.render_function(function)
377
378 def docstring_for_c_string(self, f):
379 text, add, output = _text_accumulator()
380 # turn docstring into a properly quoted C string
381 for line in f.docstring.split('\n'):
382 add('"')
383 add(quoted_for_c_string(line))
384 add('\\n"\n')
385
386 text.pop()
387 add('"')
388 return ''.join(text)
389
390 impl_prototype_template = "{c_basename}_impl({impl_parameters})"
391
392 @staticmethod
393 def template_base(*args):
394 flags = '|'.join(f for f in args if f)
395 return """
396PyDoc_STRVAR({c_basename}__doc__,
397{docstring});
398
399#define {methoddef_name} \\
Larry Hastingsebdcb502013-11-23 14:54:00 -0800400 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
401""".replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700402
Larry Hastingsebdcb502013-11-23 14:54:00 -0800403 def meth_noargs_template(self, methoddef_flags=""):
404 return self.template_base("METH_NOARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700405static {impl_return_type}
406{impl_prototype};
407
408static PyObject *
Larry Hastings3cceb382014-01-04 11:09:09 -0800409{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
Larry Hastings31826802013-10-19 00:09:25 -0700410{{
411 PyObject *return_value = NULL;
412 {declarations}
413 {initializers}
414
415 {return_value} = {c_basename}_impl({impl_arguments});
416 {return_conversion}
417
418{exit_label}
419 {cleanup}
420 return return_value;
421}}
422
423static {impl_return_type}
424{impl_prototype}
425"""
426
Larry Hastingsebdcb502013-11-23 14:54:00 -0800427 def meth_o_template(self, methoddef_flags=""):
428 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700429static PyObject *
430{c_basename}({impl_parameters})
431"""
432
Larry Hastingsebdcb502013-11-23 14:54:00 -0800433 def meth_o_return_converter_template(self, methoddef_flags=""):
434 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700435static {impl_return_type}
436{impl_prototype};
437
438static PyObject *
439{c_basename}({impl_parameters})
440{{
441 PyObject *return_value = NULL;
442 {declarations}
443 {initializers}
444 _return_value = {c_basename}_impl({impl_arguments});
445 {return_conversion}
446
447{exit_label}
448 {cleanup}
449 return return_value;
450}}
451
452static {impl_return_type}
453{impl_prototype}
454"""
455
Larry Hastingsebdcb502013-11-23 14:54:00 -0800456 def option_group_template(self, methoddef_flags=""):
457 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700458static {impl_return_type}
459{impl_prototype};
460
461static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800462{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700463{{
464 PyObject *return_value = NULL;
465 {declarations}
466 {initializers}
467
468 {option_group_parsing}
469 {return_value} = {c_basename}_impl({impl_arguments});
470 {return_conversion}
471
472{exit_label}
473 {cleanup}
474 return return_value;
475}}
476
477static {impl_return_type}
478{impl_prototype}
479"""
480
Larry Hastingsebdcb502013-11-23 14:54:00 -0800481 def keywords_template(self, methoddef_flags=""):
482 return self.template_base("METH_VARARGS|METH_KEYWORDS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700483static {impl_return_type}
484{impl_prototype};
485
486static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800487{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
Larry Hastings31826802013-10-19 00:09:25 -0700488{{
489 PyObject *return_value = NULL;
490 static char *_keywords[] = {{{keywords}, NULL}};
491 {declarations}
492 {initializers}
493
494 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
495 "{format_units}:{name}", _keywords,
496 {parse_arguments}))
497 goto exit;
498 {return_value} = {c_basename}_impl({impl_arguments});
499 {return_conversion}
500
501{exit_label}
502 {cleanup}
503 return return_value;
504}}
505
506static {impl_return_type}
507{impl_prototype}
508"""
509
Larry Hastingsebdcb502013-11-23 14:54:00 -0800510 def positional_only_template(self, methoddef_flags=""):
511 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700512static {impl_return_type}
513{impl_prototype};
514
515static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800516{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700517{{
518 PyObject *return_value = NULL;
519 {declarations}
520 {initializers}
521
522 if (!PyArg_ParseTuple(args,
523 "{format_units}:{name}",
524 {parse_arguments}))
525 goto exit;
526 {return_value} = {c_basename}_impl({impl_arguments});
527 {return_conversion}
528
529{exit_label}
530 {cleanup}
531 return return_value;
532}}
533
534static {impl_return_type}
535{impl_prototype}
536"""
537
538 @staticmethod
539 def group_to_variable_name(group):
540 adjective = "left_" if group < 0 else "right_"
541 return "group_" + adjective + str(abs(group))
542
543 def render_option_group_parsing(self, f, template_dict):
544 # positional only, grouped, optional arguments!
545 # can be optional on the left or right.
546 # here's an example:
547 #
548 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
549 #
550 # Here group D are required, and all other groups are optional.
551 # (Group D's "group" is actually None.)
552 # We can figure out which sets of arguments we have based on
553 # how many arguments are in the tuple.
554 #
555 # Note that you need to count up on both sides. For example,
556 # you could have groups C+D, or C+D+E, or C+D+E+F.
557 #
558 # What if the number of arguments leads us to an ambiguous result?
559 # Clinic prefers groups on the left. So in the above example,
560 # five arguments would map to B+C, not C+D.
561
562 add, output = text_accumulator()
563 parameters = list(f.parameters.values())
564
565 groups = []
566 group = None
567 left = []
568 right = []
569 required = []
570 last = unspecified
571
572 for p in parameters:
573 group_id = p.group
574 if group_id != last:
575 last = group_id
576 group = []
577 if group_id < 0:
578 left.append(group)
579 elif group_id == 0:
580 group = required
581 else:
582 right.append(group)
583 group.append(p)
584
585 count_min = sys.maxsize
586 count_max = -1
587
588 add("switch (PyTuple_Size(args)) {{\n")
589 for subset in permute_optional_groups(left, required, right):
590 count = len(subset)
591 count_min = min(count_min, count)
592 count_max = max(count_max, count)
593
594 group_ids = {p.group for p in subset} # eliminate duplicates
595 d = {}
596 d['count'] = count
597 d['name'] = f.name
598 d['groups'] = sorted(group_ids)
599 d['format_units'] = "".join(p.converter.format_unit for p in subset)
600
601 parse_arguments = []
602 for p in subset:
603 p.converter.parse_argument(parse_arguments)
604 d['parse_arguments'] = ", ".join(parse_arguments)
605
606 group_ids.discard(0)
607 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
608 lines = "\n".join(lines)
609
610 s = """
611 case {count}:
612 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
613 return NULL;
614 {group_booleans}
615 break;
616"""[1:]
617 s = linear_format(s, group_booleans=lines)
618 s = s.format_map(d)
619 add(s)
620
621 add(" default:\n")
622 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
623 add(s.format(f.full_name, count_min, count_max))
624 add(' return NULL;\n')
625 add("}}")
626 template_dict['option_group_parsing'] = output()
627
628 def render_function(self, f):
629 if not f:
630 return ""
631
632 add, output = text_accumulator()
633 data = CRenderData()
634
Larry Hastings31826802013-10-19 00:09:25 -0700635 parameters = list(f.parameters.values())
636 converters = [p.converter for p in parameters]
637
638 template_dict = {}
639
640 full_name = f.full_name
641 template_dict['full_name'] = full_name
642
643 name = full_name.rpartition('.')[2]
644 template_dict['name'] = name
645
646 c_basename = f.c_basename or full_name.replace(".", "_")
647 template_dict['c_basename'] = c_basename
648
649 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
650 template_dict['methoddef_name'] = methoddef_name
651
652 template_dict['docstring'] = self.docstring_for_c_string(f)
653
Larry Hastings31826802013-10-19 00:09:25 -0700654 positional = has_option_groups = False
655
656 if parameters:
657 last_group = 0
658
659 for p in parameters:
660 c = p.converter
661
662 # insert group variable
663 group = p.group
664 if last_group != group:
665 last_group = group
666 if group:
667 group_name = self.group_to_variable_name(group)
668 data.impl_arguments.append(group_name)
669 data.declarations.append("int " + group_name + " = 0;")
670 data.impl_parameters.append("int " + group_name)
671 has_option_groups = True
672 c.render(p, data)
673
674 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
675 if has_option_groups:
676 assert positional
677
Larry Hastingsebdcb502013-11-23 14:54:00 -0800678 # now insert our "self" (or whatever) parameters
679 # (we deliberately don't call render on self converters)
680 stock_self = self_converter('self', f)
681 template_dict['self_name'] = stock_self.name
682 template_dict['self_type'] = stock_self.type
683 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
684 if f.self_converter.type != stock_self.type:
685 self_cast = '(' + f.self_converter.type + ')'
686 else:
687 self_cast = ''
688 data.impl_arguments.insert(0, self_cast + stock_self.name)
689
Larry Hastings31826802013-10-19 00:09:25 -0700690 f.return_converter.render(f, data)
691 template_dict['impl_return_type'] = f.return_converter.type
692
693 template_dict['declarations'] = "\n".join(data.declarations)
694 template_dict['initializers'] = "\n\n".join(data.initializers)
695 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
696 template_dict['format_units'] = ''.join(data.format_units)
697 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
698 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
699 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
700 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
701 template_dict['cleanup'] = "".join(data.cleanup)
702 template_dict['return_value'] = data.return_value
703
704 template_dict['impl_prototype'] = self.impl_prototype_template.format_map(template_dict)
705
706 default_return_converter = (not f.return_converter or
707 f.return_converter.type == 'PyObject *')
708
709 if not parameters:
Larry Hastings3cceb382014-01-04 11:09:09 -0800710 template = self.meth_noargs_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700711 elif (len(parameters) == 1 and
712 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
713 not converters[0].is_optional() and
714 isinstance(converters[0], object_converter) and
715 converters[0].format_unit == 'O'):
716 if default_return_converter:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800717 template = self.meth_o_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700718 else:
719 # HACK
720 # we're using "impl_parameters" for the
721 # non-impl function, because that works
722 # better for METH_O. but that means we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800723 # must supress actually declaring the
Larry Hastings31826802013-10-19 00:09:25 -0700724 # impl's parameters as variables in the
725 # non-impl. but since it's METH_O, we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800726 # only have one anyway, so
727 # we don't have any problem finding it.
Larry Hastings31826802013-10-19 00:09:25 -0700728 declarations_copy = list(data.declarations)
729 before, pyobject, after = declarations_copy[0].partition('PyObject *')
730 assert not before, "hack failed, see comment"
731 assert pyobject, "hack failed, see comment"
732 assert after and after[0].isalpha(), "hack failed, see comment"
733 del declarations_copy[0]
734 template_dict['declarations'] = "\n".join(declarations_copy)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800735 template = self.meth_o_return_converter_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700736 elif has_option_groups:
737 self.render_option_group_parsing(f, template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800738 template = self.option_group_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700739 template = linear_format(template,
740 option_group_parsing=template_dict['option_group_parsing'])
741 elif positional:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800742 template = self.positional_only_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700743 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800744 template = self.keywords_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700745
746 template = linear_format(template,
747 declarations=template_dict['declarations'],
748 return_conversion=template_dict['return_conversion'],
749 initializers=template_dict['initializers'],
750 cleanup=template_dict['cleanup'],
751 )
752
753 # Only generate the "exit:" label
754 # if we have any gotos
755 need_exit_label = "goto exit;" in template
756 template = linear_format(template,
757 exit_label="exit:" if need_exit_label else ''
758 )
759
760 return template.format_map(template_dict)
761
762
763@contextlib.contextmanager
764def OverrideStdioWith(stdout):
765 saved_stdout = sys.stdout
766 sys.stdout = stdout
767 try:
768 yield
769 finally:
770 assert sys.stdout is stdout
771 sys.stdout = saved_stdout
772
773
774def create_regex(before, after):
775 """Create an re object for matching marker lines."""
776 pattern = r'^{}(\w+){}$'
777 return re.compile(pattern.format(re.escape(before), re.escape(after)))
778
779
780class Block:
781 r"""
782 Represents a single block of text embedded in
783 another file. If dsl_name is None, the block represents
784 verbatim text, raw original text from the file, in
785 which case "input" will be the only non-false member.
786 If dsl_name is not None, the block represents a Clinic
787 block.
788
789 input is always str, with embedded \n characters.
790 input represents the original text from the file;
791 if it's a Clinic block, it is the original text with
792 the body_prefix and redundant leading whitespace removed.
793
794 dsl_name is either str or None. If str, it's the text
795 found on the start line of the block between the square
796 brackets.
797
798 signatures is either list or None. If it's a list,
799 it may only contain clinic.Module, clinic.Class, and
800 clinic.Function objects. At the moment it should
801 contain at most one of each.
802
803 output is either str or None. If str, it's the output
804 from this block, with embedded '\n' characters.
805
806 indent is either str or None. It's the leading whitespace
807 that was found on every line of input. (If body_prefix is
808 not empty, this is the indent *after* removing the
809 body_prefix.)
810
811 preindent is either str or None. It's the whitespace that
812 was found in front of every line of input *before* the
813 "body_prefix" (see the Language object). If body_prefix
814 is empty, preindent must always be empty too.
815
816 To illustrate indent and preindent: Assume that '_'
817 represents whitespace. If the block processed was in a
818 Python file, and looked like this:
819 ____#/*[python]
820 ____#__for a in range(20):
821 ____#____print(a)
822 ____#[python]*/
823 "preindent" would be "____" and "indent" would be "__".
824
825 """
826 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
827 assert isinstance(input, str)
828 self.input = input
829 self.dsl_name = dsl_name
830 self.signatures = signatures or []
831 self.output = output
832 self.indent = indent
833 self.preindent = preindent
834
835
836class BlockParser:
837 """
838 Block-oriented parser for Argument Clinic.
839 Iterator, yields Block objects.
840 """
841
842 def __init__(self, input, language, *, verify=True):
843 """
844 "input" should be a str object
845 with embedded \n characters.
846
847 "language" should be a Language object.
848 """
849 language.validate()
850
851 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
852 self.block_start_line_number = self.line_number = 0
853
854 self.language = language
855 before, _, after = language.start_line.partition('{dsl_name}')
856 assert _ == '{dsl_name}'
857 self.start_re = create_regex(before, after)
858 self.verify = verify
859 self.last_checksum_re = None
860 self.last_dsl_name = None
861 self.dsl_name = None
862
863 def __iter__(self):
864 return self
865
866 def __next__(self):
867 if not self.input:
868 raise StopIteration
869
870 if self.dsl_name:
871 return_value = self.parse_clinic_block(self.dsl_name)
872 self.dsl_name = None
873 return return_value
874 return self.parse_verbatim_block()
875
876 def is_start_line(self, line):
877 match = self.start_re.match(line.lstrip())
878 return match.group(1) if match else None
879
880 def _line(self):
881 self.line_number += 1
882 return self.input.pop()
883
884 def parse_verbatim_block(self):
885 add, output = text_accumulator()
886 self.block_start_line_number = self.line_number
887
888 while self.input:
889 line = self._line()
890 dsl_name = self.is_start_line(line)
891 if dsl_name:
892 self.dsl_name = dsl_name
893 break
894 add(line)
895
896 return Block(output())
897
898 def parse_clinic_block(self, dsl_name):
899 input_add, input_output = text_accumulator()
900 self.block_start_line_number = self.line_number + 1
901 stop_line = self.language.stop_line.format(dsl_name=dsl_name) + '\n'
902 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
903
904 # consume body of program
905 while self.input:
906 line = self._line()
907 if line == stop_line or self.is_start_line(line):
908 break
909 if body_prefix:
910 line = line.lstrip()
911 assert line.startswith(body_prefix)
912 line = line[len(body_prefix):]
913 input_add(line)
914
915 # consume output and checksum line, if present.
916 if self.last_dsl_name == dsl_name:
917 checksum_re = self.last_checksum_re
918 else:
919 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
920 assert _ == '{checksum}'
921 checksum_re = create_regex(before, after)
922 self.last_dsl_name = dsl_name
923 self.last_checksum_re = checksum_re
924
925 # scan forward for checksum line
926 output_add, output_output = text_accumulator()
927 checksum = None
928 while self.input:
929 line = self._line()
930 match = checksum_re.match(line.lstrip())
931 checksum = match.group(1) if match else None
932 if checksum:
933 break
934 output_add(line)
935 if self.is_start_line(line):
936 break
937
Larry Hastingsef3b1fb2013-10-22 23:26:23 -0700938 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -0700939 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -0700940 if self.verify:
941 computed = compute_checksum(output)
942 if checksum != computed:
943 fail("Checksum mismatch!\nExpected: {}\nComputed: {}".format(checksum, computed))
944 else:
945 # put back output
946 self.input.extend(reversed(output.splitlines(keepends=True)))
947 self.line_number -= len(output)
948 output = None
949
950 return Block(input_output(), dsl_name, output=output)
951
952
953class BlockPrinter:
954
955 def __init__(self, language, f=None):
956 self.language = language
957 self.f = f or io.StringIO()
958
959 def print_block(self, block):
960 input = block.input
961 output = block.output
962 dsl_name = block.dsl_name
963 write = self.f.write
964
Larry Hastings31826802013-10-19 00:09:25 -0700965 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
966
967 if not dsl_name:
968 write(input)
969 return
970
971 write(self.language.start_line.format(dsl_name=dsl_name))
972 write("\n")
973
974 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
975 if not body_prefix:
976 write(input)
977 else:
978 for line in input.split('\n'):
979 write(body_prefix)
980 write(line)
981 write("\n")
982
983 write(self.language.stop_line.format(dsl_name=dsl_name))
984 write("\n")
985
986 output = block.output
987 if output:
988 write(output)
989 if not output.endswith('\n'):
990 write('\n')
991
992 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
993 write("\n")
994
995
996# maps strings to Language objects.
997# "languages" maps the name of the language ("C", "Python").
998# "extensions" maps the file extension ("c", "py").
999languages = { 'C': CLanguage, 'Python': PythonLanguage }
1000extensions = { 'c': CLanguage, 'h': CLanguage, 'py': PythonLanguage }
1001
1002
1003# maps strings to callables.
1004# these callables must be of the form:
1005# def foo(name, default, *, ...)
1006# The callable may have any number of keyword-only parameters.
1007# The callable must return a CConverter object.
1008# The callable should not call builtins.print.
1009converters = {}
1010
1011# maps strings to callables.
1012# these callables follow the same rules as those for "converters" above.
1013# note however that they will never be called with keyword-only parameters.
1014legacy_converters = {}
1015
1016
1017# maps strings to callables.
1018# these callables must be of the form:
1019# def foo(*, ...)
1020# The callable may have any number of keyword-only parameters.
1021# The callable must return a CConverter object.
1022# The callable should not call builtins.print.
1023return_converters = {}
1024
1025class Clinic:
1026 def __init__(self, language, printer=None, *, verify=True, filename=None):
1027 # maps strings to Parser objects.
1028 # (instantiated from the "parsers" global.)
1029 self.parsers = {}
1030 self.language = language
1031 self.printer = printer or BlockPrinter(language)
1032 self.verify = verify
1033 self.filename = filename
1034 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001035 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -07001036
1037 global clinic
1038 clinic = self
1039
1040 def parse(self, input):
1041 printer = self.printer
1042 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1043 for block in self.block_parser:
1044 dsl_name = block.dsl_name
1045 if dsl_name:
1046 if dsl_name not in self.parsers:
1047 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1048 self.parsers[dsl_name] = parsers[dsl_name](self)
1049 parser = self.parsers[dsl_name]
1050 parser.parse(block)
1051 printer.print_block(block)
1052 return printer.f.getvalue()
1053
1054 def _module_and_class(self, fields):
1055 """
1056 fields should be an iterable of field names.
1057 returns a tuple of (module, class).
1058 the module object could actually be self (a clinic object).
1059 this function is only ever used to find the parent of where
1060 a new class/module should go.
1061 """
1062 in_classes = False
1063 parent = module = self
1064 cls = None
1065 so_far = []
1066
1067 for field in fields:
1068 so_far.append(field)
1069 if not in_classes:
1070 child = parent.modules.get(field)
1071 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001072 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001073 continue
1074 in_classes = True
1075 if not hasattr(parent, 'classes'):
1076 return module, cls
1077 child = parent.classes.get(field)
1078 if not child:
1079 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1080 cls = parent = child
1081
1082 return module, cls
1083
1084
1085def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1086 extension = os.path.splitext(filename)[1][1:]
1087 if not extension:
1088 fail("Can't extract file type for file " + repr(filename))
1089
1090 try:
1091 language = extensions[extension]()
1092 except KeyError:
1093 fail("Can't identify file type for file " + repr(filename))
1094
1095 clinic = Clinic(language, verify=verify, filename=filename)
1096
1097 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001098 raw = f.read()
1099
1100 cooked = clinic.parse(raw)
1101 if cooked == raw:
1102 return
Larry Hastings31826802013-10-19 00:09:25 -07001103
1104 directory = os.path.dirname(filename) or '.'
1105
1106 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001107 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001108 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1109 with open(tmpfilename, "wb") as f:
1110 f.write(bytes)
1111 os.replace(tmpfilename, output or filename)
1112
1113
1114def compute_checksum(input):
1115 input = input or ''
1116 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1117
1118
1119
1120
1121class PythonParser:
1122 def __init__(self, clinic):
1123 pass
1124
1125 def parse(self, block):
1126 s = io.StringIO()
1127 with OverrideStdioWith(s):
1128 exec(block.input)
1129 block.output = s.getvalue()
1130
1131
1132class Module:
1133 def __init__(self, name, module=None):
1134 self.name = name
1135 self.module = self.parent = module
1136
1137 self.modules = collections.OrderedDict()
1138 self.classes = collections.OrderedDict()
1139 self.functions = []
1140
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001141 def __repr__(self):
1142 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1143
Larry Hastings31826802013-10-19 00:09:25 -07001144class Class:
1145 def __init__(self, name, module=None, cls=None):
1146 self.name = name
1147 self.module = module
1148 self.cls = cls
1149 self.parent = cls or module
1150
1151 self.classes = collections.OrderedDict()
1152 self.functions = []
1153
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001154 def __repr__(self):
1155 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1156
1157
Larry Hastings31826802013-10-19 00:09:25 -07001158DATA, CALLABLE, METHOD, STATIC_METHOD, CLASS_METHOD = range(5)
1159
1160class Function:
1161 """
1162 Mutable duck type for inspect.Function.
1163
1164 docstring - a str containing
1165 * embedded line breaks
1166 * text outdented to the left margin
1167 * no trailing whitespace.
1168 It will always be true that
1169 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1170 """
1171
1172 def __init__(self, parameters=None, *, name,
1173 module, cls=None, c_basename=None,
1174 full_name=None,
1175 return_converter, return_annotation=_empty,
1176 docstring=None, kind=CALLABLE, coexist=False):
1177 self.parameters = parameters or collections.OrderedDict()
1178 self.return_annotation = return_annotation
1179 self.name = name
1180 self.full_name = full_name
1181 self.module = module
1182 self.cls = cls
1183 self.parent = cls or module
1184 self.c_basename = c_basename
1185 self.return_converter = return_converter
1186 self.docstring = docstring or ''
1187 self.kind = kind
1188 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001189 self.self_converter = None
1190
1191 @property
1192 def methoddef_flags(self):
1193 flags = []
1194 if self.kind == CLASS_METHOD:
1195 flags.append('METH_CLASS')
1196 elif self.kind == STATIC_METHOD:
1197 flags.append('METH_STATIC')
1198 else:
1199 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1200 if self.coexist:
1201 flags.append('METH_COEXIST')
1202 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001203
1204 def __repr__(self):
1205 return '<clinic.Function ' + self.name + '>'
1206
1207
1208class Parameter:
1209 """
1210 Mutable duck type of inspect.Parameter.
1211 """
1212
1213 def __init__(self, name, kind, *, default=_empty,
1214 function, converter, annotation=_empty,
1215 docstring=None, group=0):
1216 self.name = name
1217 self.kind = kind
1218 self.default = default
1219 self.function = function
1220 self.converter = converter
1221 self.annotation = annotation
1222 self.docstring = docstring or ''
1223 self.group = group
1224
1225 def __repr__(self):
1226 return '<clinic.Parameter ' + self.name + '>'
1227
1228 def is_keyword_only(self):
1229 return self.kind == inspect.Parameter.KEYWORD_ONLY
1230
1231py_special_values = {
1232 NULL: "None",
1233}
1234
1235def py_repr(o):
1236 special = py_special_values.get(o)
1237 if special:
1238 return special
1239 return repr(o)
1240
1241
1242c_special_values = {
1243 NULL: "NULL",
1244 None: "Py_None",
1245}
1246
1247def c_repr(o):
1248 special = c_special_values.get(o)
1249 if special:
1250 return special
1251 if isinstance(o, str):
1252 return '"' + quoted_for_c_string(o) + '"'
1253 return repr(o)
1254
1255def add_c_converter(f, name=None):
1256 if not name:
1257 name = f.__name__
1258 if not name.endswith('_converter'):
1259 return f
1260 name = name[:-len('_converter')]
1261 converters[name] = f
1262 return f
1263
1264def add_default_legacy_c_converter(cls):
1265 # automatically add converter for default format unit
1266 # (but without stomping on the existing one if it's already
1267 # set, in case you subclass)
1268 if ((cls.format_unit != 'O&') and
1269 (cls.format_unit not in legacy_converters)):
1270 legacy_converters[cls.format_unit] = cls
1271 return cls
1272
1273def add_legacy_c_converter(format_unit, **kwargs):
1274 """
1275 Adds a legacy converter.
1276 """
1277 def closure(f):
1278 if not kwargs:
1279 added_f = f
1280 else:
1281 added_f = functools.partial(f, **kwargs)
1282 legacy_converters[format_unit] = added_f
1283 return f
1284 return closure
1285
1286class CConverterAutoRegister(type):
1287 def __init__(cls, name, bases, classdict):
1288 add_c_converter(cls)
1289 add_default_legacy_c_converter(cls)
1290
1291class CConverter(metaclass=CConverterAutoRegister):
1292 """
1293 For the init function, self, name, function, and default
1294 must be keyword-or-positional parameters. All other
1295 parameters (including "required" and "doc_default")
1296 must be keyword-only.
1297 """
1298
Larry Hastings78cf85c2014-01-04 12:44:57 -08001299 # The C type to use for this variable.
1300 # 'type' should be a Python string specifying the type, e.g. "int".
1301 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001302 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001303
1304 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001305 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001306 default = unspecified
1307
Larry Hastings31826802013-10-19 00:09:25 -07001308 # "default" as it should appear in the documentation, as a string.
1309 # Or None if there is no default.
1310 doc_default = None
1311
Larry Hastingsabc716b2013-11-20 09:13:52 -08001312 # "default" converted into a str for rendering into Python code.
1313 py_default = None
1314
Larry Hastings31826802013-10-19 00:09:25 -07001315 # "default" converted into a C value, as a string.
1316 # Or None if there is no default.
1317 c_default = None
1318
Larry Hastingsabc716b2013-11-20 09:13:52 -08001319 # The default value used to initialize the C variable when
1320 # there is no default, but not specifying a default may
1321 # result in an "uninitialized variable" warning. This can
1322 # easily happen when using option groups--although
1323 # properly-written code won't actually use the variable,
1324 # the variable does get passed in to the _impl. (Ah, if
1325 # only dataflow analysis could inline the static function!)
1326 #
1327 # This value is specified as a string.
1328 # Every non-abstract subclass should supply a valid value.
1329 c_ignored_default = 'NULL'
1330
Larry Hastings31826802013-10-19 00:09:25 -07001331 # The C converter *function* to be used, if any.
1332 # (If this is not None, format_unit must be 'O&'.)
1333 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001334
Larry Hastings78cf85c2014-01-04 12:44:57 -08001335 # Should Argument Clinic add a '&' before the name of
1336 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001337 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001338
1339 # Should Argument Clinic add a '&' before the name of
1340 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001341 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001342
1343 #############################################################
1344 #############################################################
1345 ## You shouldn't need to read anything below this point to ##
1346 ## write your own converter functions. ##
1347 #############################################################
1348 #############################################################
1349
1350 # The "format unit" to specify for this variable when
1351 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1352 # Custom converters should always use the default value of 'O&'.
1353 format_unit = 'O&'
1354
1355 # What encoding do we want for this variable? Only used
1356 # by format units starting with 'e'.
1357 encoding = None
1358
1359 # Do we want an adjacent '_length' variable for this variable?
1360 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001361 length = False
1362
1363 def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs):
1364 self.function = function
1365 self.name = name
1366
1367 if default is not unspecified:
1368 self.default = default
1369 self.py_default = py_repr(default)
1370 self.doc_default = doc_default if doc_default is not None else self.py_default
1371 self.c_default = c_repr(default)
1372 elif doc_default is not None:
1373 fail(function.fullname + " argument " + name + " specified a 'doc_default' without having a 'default'")
1374 if annotation != unspecified:
1375 fail("The 'annotation' parameter is not currently permitted.")
1376 self.required = required
1377 self.converter_init(**kwargs)
1378
1379 def converter_init(self):
1380 pass
1381
1382 def is_optional(self):
1383 return (self.default is not unspecified) and (not self.required)
1384
1385 def render(self, parameter, data):
1386 """
1387 parameter is a clinic.Parameter instance.
1388 data is a CRenderData instance.
1389 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001390 self.parameter = parameter
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001391 name = ensure_legal_c_identifier(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07001392
1393 # declarations
1394 d = self.declaration()
1395 data.declarations.append(d)
1396
1397 # initializers
1398 initializers = self.initialize()
1399 if initializers:
1400 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1401
1402 # impl_arguments
1403 s = ("&" if self.impl_by_reference else "") + name
1404 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001405 if self.length:
1406 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001407
1408 # keywords
1409 data.keywords.append(name)
1410
1411 # format_units
1412 if self.is_optional() and '|' not in data.format_units:
1413 data.format_units.append('|')
1414 if parameter.is_keyword_only() and '$' not in data.format_units:
1415 data.format_units.append('$')
1416 data.format_units.append(self.format_unit)
1417
1418 # parse_arguments
1419 self.parse_argument(data.parse_arguments)
1420
1421 # impl_parameters
1422 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001423 if self.length:
1424 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001425
1426 # cleanup
1427 cleanup = self.cleanup()
1428 if cleanup:
1429 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1430
Larry Hastingsebdcb502013-11-23 14:54:00 -08001431 def length_name(self):
1432 """Computes the name of the associated "length" variable."""
1433 if not self.length:
1434 return None
1435 return ensure_legal_c_identifier(self.name) + "_length"
1436
Larry Hastings31826802013-10-19 00:09:25 -07001437 # Why is this one broken out separately?
1438 # For "positional-only" function parsing,
1439 # which generates a bunch of PyArg_ParseTuple calls.
1440 def parse_argument(self, list):
1441 assert not (self.converter and self.encoding)
1442 if self.format_unit == 'O&':
1443 assert self.converter
1444 list.append(self.converter)
1445
1446 if self.encoding:
1447 list.append(self.encoding)
1448
Larry Hastingsebdcb502013-11-23 14:54:00 -08001449 legal_name = ensure_legal_c_identifier(self.name)
1450 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001451 list.append(s)
1452
Larry Hastingsebdcb502013-11-23 14:54:00 -08001453 if self.length:
1454 list.append("&" + self.length_name())
1455
Larry Hastings31826802013-10-19 00:09:25 -07001456 #
1457 # All the functions after here are intended as extension points.
1458 #
1459
1460 def simple_declaration(self, by_reference=False):
1461 """
1462 Computes the basic declaration of the variable.
1463 Used in computing the prototype declaration and the
1464 variable declaration.
1465 """
1466 prototype = [self.type]
1467 if by_reference or not self.type.endswith('*'):
1468 prototype.append(" ")
1469 if by_reference:
1470 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001471 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001472 return "".join(prototype)
1473
1474 def declaration(self):
1475 """
1476 The C statement to declare this variable.
1477 """
1478 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08001479 default = self.c_default
1480 if not default and self.parameter.group:
1481 default = self.c_ignored_default
1482 if default:
Larry Hastings31826802013-10-19 00:09:25 -07001483 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08001484 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07001485 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001486 if self.length:
1487 declaration.append('\nPy_ssize_clean_t ')
1488 declaration.append(self.length_name())
1489 declaration.append(';')
Larry Hastings31826802013-10-19 00:09:25 -07001490 return "".join(declaration)
1491
1492 def initialize(self):
1493 """
1494 The C statements required to set up this variable before parsing.
1495 Returns a string containing this code indented at column 0.
1496 If no initialization is necessary, returns an empty string.
1497 """
1498 return ""
1499
1500 def cleanup(self):
1501 """
1502 The C statements required to clean up after this variable.
1503 Returns a string containing this code indented at column 0.
1504 If no cleanup is necessary, returns an empty string.
1505 """
1506 return ""
1507
1508
1509class bool_converter(CConverter):
1510 type = 'int'
1511 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001512 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07001513
1514 def converter_init(self):
1515 self.default = bool(self.default)
1516 self.c_default = str(int(self.default))
1517
1518class char_converter(CConverter):
1519 type = 'char'
1520 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001521 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001522
1523@add_legacy_c_converter('B', bitwise=True)
1524class byte_converter(CConverter):
1525 type = 'byte'
1526 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001527 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001528
1529 def converter_init(self, *, bitwise=False):
1530 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001531 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07001532
1533class short_converter(CConverter):
1534 type = 'short'
1535 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001536 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001537
1538class unsigned_short_converter(CConverter):
1539 type = 'unsigned short'
1540 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001541 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001542
1543 def converter_init(self, *, bitwise=False):
1544 if not bitwise:
1545 fail("Unsigned shorts must be bitwise (for now).")
1546
Larry Hastingsebdcb502013-11-23 14:54:00 -08001547@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07001548class int_converter(CConverter):
1549 type = 'int'
1550 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001551 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001552
Larry Hastingsebdcb502013-11-23 14:54:00 -08001553 def converter_init(self, *, types='int'):
1554 if types == 'str':
1555 self.format_unit = 'C'
1556 elif types != 'int':
1557 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07001558
1559class unsigned_int_converter(CConverter):
1560 type = 'unsigned int'
1561 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001562 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001563
1564 def converter_init(self, *, bitwise=False):
1565 if not bitwise:
1566 fail("Unsigned ints must be bitwise (for now).")
1567
1568class long_converter(CConverter):
1569 type = 'long'
1570 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001571 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001572
1573class unsigned_long_converter(CConverter):
1574 type = 'unsigned long'
1575 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001576 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001577
1578 def converter_init(self, *, bitwise=False):
1579 if not bitwise:
1580 fail("Unsigned longs must be bitwise (for now).")
1581
1582class PY_LONG_LONG_converter(CConverter):
1583 type = 'PY_LONG_LONG'
1584 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001585 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001586
1587class unsigned_PY_LONG_LONG_converter(CConverter):
1588 type = 'unsigned PY_LONG_LONG'
1589 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001590 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001591
1592 def converter_init(self, *, bitwise=False):
1593 if not bitwise:
1594 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
1595
1596class Py_ssize_t_converter(CConverter):
1597 type = 'Py_ssize_t'
1598 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001599 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001600
1601
1602class float_converter(CConverter):
1603 type = 'float'
1604 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001605 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001606
1607class double_converter(CConverter):
1608 type = 'double'
1609 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001610 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001611
1612
1613class Py_complex_converter(CConverter):
1614 type = 'Py_complex'
1615 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001616 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07001617
1618
1619class object_converter(CConverter):
1620 type = 'PyObject *'
1621 format_unit = 'O'
1622
1623 def converter_init(self, *, type=None):
1624 if type:
1625 assert isinstance(type, str)
1626 assert type.isidentifier()
1627 try:
1628 type = eval(type)
1629 # need more of these!
1630 type = {
1631 str: '&PyUnicode_Type',
1632 }[type]
1633 except NameError:
1634 type = type
1635 self.format_unit = 'O!'
1636 self.encoding = type
1637
1638
Larry Hastingsebdcb502013-11-23 14:54:00 -08001639@add_legacy_c_converter('s#', length=True)
1640@add_legacy_c_converter('y', type="bytes")
1641@add_legacy_c_converter('y#', type="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001642@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001643@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001644class str_converter(CConverter):
1645 type = 'const char *'
1646 format_unit = 's'
1647
Larry Hastingsebdcb502013-11-23 14:54:00 -08001648 def converter_init(self, *, encoding=None, types="str",
1649 length=False, nullable=False, zeroes=False):
1650
1651 types = set(types.strip().split())
1652 bytes_type = set(("bytes",))
1653 str_type = set(("str",))
1654 all_3_type = set(("bytearray",)) | bytes_type | str_type
1655 is_bytes = types == bytes_type
1656 is_str = types == str_type
1657 is_all_3 = types == all_3_type
1658
1659 self.length = bool(length)
1660 format_unit = None
1661
1662 if encoding:
1663 self.encoding = encoding
1664
1665 if is_str and not (length or zeroes or nullable):
1666 format_unit = 'es'
1667 elif is_all_3 and not (length or zeroes or nullable):
1668 format_unit = 'et'
1669 elif is_str and length and zeroes and not nullable:
1670 format_unit = 'es#'
1671 elif is_all_3 and length and not (nullable or zeroes):
1672 format_unit = 'et#'
1673
1674 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08001675 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001676 # TODO set pointer to NULL
1677 # TODO add cleanup for buffer
1678 pass
1679
1680 else:
1681 if zeroes:
1682 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
1683
1684 if is_bytes and not (nullable or length):
1685 format_unit = 'y'
1686 elif is_bytes and length and not nullable:
1687 format_unit = 'y#'
1688 elif is_str and not (nullable or length):
1689 format_unit = 's'
1690 elif is_str and length and not nullable:
1691 format_unit = 's#'
1692 elif is_str and nullable and not length:
1693 format_unit = 'z'
1694 elif is_str and nullable and length:
1695 format_unit = 'z#'
1696
1697 if not format_unit:
1698 fail("str_converter: illegal combination of arguments")
1699 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001700
1701
1702class PyBytesObject_converter(CConverter):
1703 type = 'PyBytesObject *'
1704 format_unit = 'S'
1705
1706class PyByteArrayObject_converter(CConverter):
1707 type = 'PyByteArrayObject *'
1708 format_unit = 'Y'
1709
1710class unicode_converter(CConverter):
1711 type = 'PyObject *'
1712 format_unit = 'U'
1713
Larry Hastingsebdcb502013-11-23 14:54:00 -08001714@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001715@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001716@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001717class Py_UNICODE_converter(CConverter):
1718 type = 'Py_UNICODE *'
1719 format_unit = 'u'
1720
Larry Hastingsebdcb502013-11-23 14:54:00 -08001721 def converter_init(self, *, nullable=False, length=False):
1722 format_unit = 'Z' if nullable else 'u'
1723 if length:
1724 format_unit += '#'
1725 self.length = True
1726 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001727
Larry Hastingsebdcb502013-11-23 14:54:00 -08001728#
1729# We define three string conventions for buffer types in the 'types' argument:
1730# 'buffer' : any object supporting the buffer interface
1731# 'rwbuffer': any object supporting the buffer interface, but must be writeable
1732# 'robuffer': any object supporting the buffer interface, but must not be writeable
1733#
1734@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
1735@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
1736@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07001737class Py_buffer_converter(CConverter):
1738 type = 'Py_buffer'
1739 format_unit = 'y*'
1740 impl_by_reference = True
Larry Hastingsabc716b2013-11-20 09:13:52 -08001741 c_ignored_default = "{NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07001742
Larry Hastingsebdcb502013-11-23 14:54:00 -08001743 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
1744 types = set(types.strip().split())
1745 bytes_type = set(('bytes',))
1746 bytearray_type = set(('bytearray',))
1747 buffer_type = set(('buffer',))
1748 rwbuffer_type = set(('rwbuffer',))
1749 robuffer_type = set(('robuffer',))
1750 str_type = set(('str',))
1751 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
1752
1753 format_unit = None
1754 if types == (str_type | bytes_bytearray_buffer_type):
1755 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07001756 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001757 if nullable:
1758 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
1759 elif types == (bytes_bytearray_buffer_type):
1760 format_unit = 'y*'
1761 elif types == (bytearray_type | rwuffer_type):
1762 format_unit = 'w*'
1763 if not format_unit:
1764 fail("Py_buffer_converter: illegal combination of arguments")
1765
1766 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001767
1768 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001769 name = ensure_legal_c_identifier(self.name)
1770 return "".join(["if (", name, ".buf)\n PyBuffer_Release(&", name, ");\n"])
1771
1772
1773class self_converter(CConverter):
1774 """
1775 A special-case converter:
1776 this is the default converter used for "self".
1777 """
1778 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08001779 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001780 f = self.function
1781 if f.kind == CALLABLE:
1782 if f.cls:
1783 self.name = "self"
1784 else:
1785 self.name = "module"
1786 self.type = "PyModuleDef *"
1787 elif f.kind == STATIC_METHOD:
1788 self.name = "null"
1789 self.type = "void *"
1790 elif f.kind == CLASS_METHOD:
1791 self.name = "cls"
1792 self.type = "PyTypeObject *"
1793
Larry Hastings78cf85c2014-01-04 12:44:57 -08001794 if type:
1795 self.type = type
1796
Larry Hastingsebdcb502013-11-23 14:54:00 -08001797 def render(self, parameter, data):
1798 fail("render() should never be called on self_converter instances")
1799
Larry Hastings31826802013-10-19 00:09:25 -07001800
1801
1802def add_c_return_converter(f, name=None):
1803 if not name:
1804 name = f.__name__
1805 if not name.endswith('_return_converter'):
1806 return f
1807 name = name[:-len('_return_converter')]
1808 return_converters[name] = f
1809 return f
1810
1811
1812class CReturnConverterAutoRegister(type):
1813 def __init__(cls, name, bases, classdict):
1814 add_c_return_converter(cls)
1815
1816class CReturnConverter(metaclass=CReturnConverterAutoRegister):
1817
Larry Hastings78cf85c2014-01-04 12:44:57 -08001818 # The C type to use for this variable.
1819 # 'type' should be a Python string specifying the type, e.g. "int".
1820 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001821 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08001822
1823 # The Python default value for this parameter, as a Python value.
1824 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001825 default = None
1826
1827 def __init__(self, *, doc_default=None, **kwargs):
1828 self.doc_default = doc_default
1829 try:
1830 self.return_converter_init(**kwargs)
1831 except TypeError as e:
1832 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
1833 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
1834
1835 def return_converter_init(self):
1836 pass
1837
1838 def declare(self, data, name="_return_value"):
1839 line = []
1840 add = line.append
1841 add(self.type)
1842 if not self.type.endswith('*'):
1843 add(' ')
1844 add(name + ';')
1845 data.declarations.append(''.join(line))
1846 data.return_value = name
1847
1848 def err_occurred_if(self, expr, data):
1849 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
1850
1851 def err_occurred_if_null_pointer(self, variable, data):
1852 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
1853
1854 def render(self, function, data):
1855 """
1856 function is a clinic.Function instance.
1857 data is a CRenderData instance.
1858 """
1859 pass
1860
1861add_c_return_converter(CReturnConverter, 'object')
1862
Larry Hastings78cf85c2014-01-04 12:44:57 -08001863class NoneType_return_converter(CReturnConverter):
1864 def render(self, function, data):
1865 self.declare(data)
1866 data.return_conversion.append('''
1867if (_return_value != Py_None)
1868 goto exit;
1869return_value = Py_None;
1870Py_INCREF(Py_None);
1871'''.strip())
1872
Larry Hastings31826802013-10-19 00:09:25 -07001873class int_return_converter(CReturnConverter):
1874 type = 'int'
1875
1876 def render(self, function, data):
1877 self.declare(data)
1878 self.err_occurred_if("_return_value == -1", data)
1879 data.return_conversion.append(
1880 'return_value = PyLong_FromLong((long)_return_value);\n')
1881
1882
1883class long_return_converter(CReturnConverter):
1884 type = 'long'
1885
1886 def render(self, function, data):
1887 self.declare(data)
1888 self.err_occurred_if("_return_value == -1", data)
1889 data.return_conversion.append(
1890 'return_value = PyLong_FromLong(_return_value);\n')
1891
1892
1893class Py_ssize_t_return_converter(CReturnConverter):
1894 type = 'Py_ssize_t'
1895
1896 def render(self, function, data):
1897 self.declare(data)
1898 self.err_occurred_if("_return_value == -1", data)
1899 data.return_conversion.append(
1900 'return_value = PyLong_FromSsize_t(_return_value);\n')
1901
1902
1903class DecodeFSDefault_return_converter(CReturnConverter):
1904 type = 'char *'
1905
1906 def render(self, function, data):
1907 self.declare(data)
1908 self.err_occurred_if_null_pointer("_return_value", data)
1909 data.return_conversion.append(
1910 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
1911
1912
1913class IndentStack:
1914 def __init__(self):
1915 self.indents = []
1916 self.margin = None
1917
1918 def _ensure(self):
1919 if not self.indents:
1920 fail('IndentStack expected indents, but none are defined.')
1921
1922 def measure(self, line):
1923 """
1924 Returns the length of the line's margin.
1925 """
1926 if '\t' in line:
1927 fail('Tab characters are illegal in the Clinic DSL.')
1928 stripped = line.lstrip()
1929 if not len(stripped):
1930 # we can't tell anything from an empty line
1931 # so just pretend it's indented like our current indent
1932 self._ensure()
1933 return self.indents[-1]
1934 return len(line) - len(stripped)
1935
1936 def infer(self, line):
1937 """
1938 Infer what is now the current margin based on this line.
1939 Returns:
1940 1 if we have indented (or this is the first margin)
1941 0 if the margin has not changed
1942 -N if we have dedented N times
1943 """
1944 indent = self.measure(line)
1945 margin = ' ' * indent
1946 if not self.indents:
1947 self.indents.append(indent)
1948 self.margin = margin
1949 return 1
1950 current = self.indents[-1]
1951 if indent == current:
1952 return 0
1953 if indent > current:
1954 self.indents.append(indent)
1955 self.margin = margin
1956 return 1
1957 # indent < current
1958 if indent not in self.indents:
1959 fail("Illegal outdent.")
1960 outdent_count = 0
1961 while indent != current:
1962 self.indents.pop()
1963 current = self.indents[-1]
1964 outdent_count -= 1
1965 self.margin = margin
1966 return outdent_count
1967
1968 @property
1969 def depth(self):
1970 """
1971 Returns how many margins are currently defined.
1972 """
1973 return len(self.indents)
1974
1975 def indent(self, line):
1976 """
1977 Indents a line by the currently defined margin.
1978 """
1979 return self.margin + line
1980
1981 def dedent(self, line):
1982 """
1983 Dedents a line by the currently defined margin.
1984 (The inverse of 'indent'.)
1985 """
1986 margin = self.margin
1987 indent = self.indents[-1]
1988 if not line.startswith(margin):
1989 fail('Cannot dedent, line does not start with the previous margin:')
1990 return line[indent:]
1991
1992
1993class DSLParser:
1994 def __init__(self, clinic):
1995 self.clinic = clinic
1996
1997 self.directives = {}
1998 for name in dir(self):
1999 # functions that start with directive_ are added to directives
2000 _, s, key = name.partition("directive_")
2001 if s:
2002 self.directives[key] = getattr(self, name)
2003
2004 # functions that start with at_ are too, with an @ in front
2005 _, s, key = name.partition("at_")
2006 if s:
2007 self.directives['@' + key] = getattr(self, name)
2008
2009 self.reset()
2010
2011 def reset(self):
2012 self.function = None
2013 self.state = self.state_dsl_start
2014 self.parameter_indent = None
2015 self.keyword_only = False
2016 self.group = 0
2017 self.parameter_state = self.ps_start
2018 self.indent = IndentStack()
2019 self.kind = CALLABLE
2020 self.coexist = False
2021
Larry Hastingsebdcb502013-11-23 14:54:00 -08002022 def directive_version(self, required):
2023 global version
2024 if version_comparitor(version, required) < 0:
2025 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2026
Larry Hastings31826802013-10-19 00:09:25 -07002027 def directive_module(self, name):
2028 fields = name.split('.')
2029 new = fields.pop()
2030 module, cls = self.clinic._module_and_class(fields)
2031 if cls:
2032 fail("Can't nest a module inside a class!")
2033 m = Module(name, module)
2034 module.modules[name] = m
2035 self.block.signatures.append(m)
2036
2037 def directive_class(self, name):
2038 fields = name.split('.')
2039 in_classes = False
2040 parent = self
2041 name = fields.pop()
2042 so_far = []
2043 module, cls = self.clinic._module_and_class(fields)
2044
Larry Hastings31826802013-10-19 00:09:25 -07002045 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002046 if cls:
2047 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002048 else:
2049 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002050 self.block.signatures.append(c)
2051
2052 def at_classmethod(self):
2053 assert self.kind is CALLABLE
2054 self.kind = CLASS_METHOD
2055
2056 def at_staticmethod(self):
2057 assert self.kind is CALLABLE
2058 self.kind = STATIC_METHOD
2059
2060 def at_coexist(self):
2061 assert self.coexist == False
2062 self.coexist = True
2063
Larry Hastingsebdcb502013-11-23 14:54:00 -08002064
Larry Hastings31826802013-10-19 00:09:25 -07002065 def parse(self, block):
2066 self.reset()
2067 self.block = block
2068 block_start = self.clinic.block_parser.line_number
2069 lines = block.input.split('\n')
2070 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2071 if '\t' in line:
2072 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2073 self.state(line)
2074
2075 self.next(self.state_terminal)
2076 self.state(None)
2077
2078 block.output = self.clinic.language.render(block.signatures)
2079
2080 @staticmethod
2081 def ignore_line(line):
2082 # ignore comment-only lines
2083 if line.lstrip().startswith('#'):
2084 return True
2085
2086 # Ignore empty lines too
2087 # (but not in docstring sections!)
2088 if not line.strip():
2089 return True
2090
2091 return False
2092
2093 @staticmethod
2094 def calculate_indent(line):
2095 return len(line) - len(line.strip())
2096
2097 def next(self, state, line=None):
2098 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2099 self.state = state
2100 if line is not None:
2101 self.state(line)
2102
2103 def state_dsl_start(self, line):
2104 # self.block = self.ClinicOutputBlock(self)
2105 if self.ignore_line(line):
2106 return
2107 self.next(self.state_modulename_name, line)
2108
2109 def state_modulename_name(self, line):
2110 # looking for declaration, which establishes the leftmost column
2111 # line should be
2112 # modulename.fnname [as c_basename] [-> return annotation]
2113 # square brackets denote optional syntax.
2114 #
2115 # (but we might find a directive first!)
2116 #
2117 # this line is permitted to start with whitespace.
2118 # we'll call this number of spaces F (for "function").
2119
2120 if not line.strip():
2121 return
2122
2123 self.indent.infer(line)
2124
2125 # is it a directive?
2126 fields = shlex.split(line)
2127 directive_name = fields[0]
2128 directive = self.directives.get(directive_name, None)
2129 if directive:
2130 directive(*fields[1:])
2131 return
2132
2133 line, _, returns = line.partition('->')
2134
2135 full_name, _, c_basename = line.partition(' as ')
2136 full_name = full_name.strip()
2137 c_basename = c_basename.strip() or None
2138
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002139 if not is_legal_py_identifier(full_name):
2140 fail("Illegal function name: {}".format(full_name))
2141 if c_basename and not is_legal_c_identifier(c_basename):
2142 fail("Illegal C basename: {}".format(c_basename))
2143
Larry Hastings31826802013-10-19 00:09:25 -07002144 if not returns:
2145 return_converter = CReturnConverter()
2146 else:
2147 ast_input = "def x() -> {}: pass".format(returns)
2148 module = None
2149 try:
2150 module = ast.parse(ast_input)
2151 except SyntaxError:
2152 pass
2153 if not module:
2154 fail("Badly-formed annotation for " + full_name + ": " + returns)
2155 try:
2156 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
2157 assert not legacy
2158 if name not in return_converters:
2159 fail("Error: No available return converter called " + repr(name))
2160 return_converter = return_converters[name](**kwargs)
2161 except ValueError:
2162 fail("Badly-formed annotation for " + full_name + ": " + returns)
2163
2164 fields = [x.strip() for x in full_name.split('.')]
2165 function_name = fields.pop()
2166 module, cls = self.clinic._module_and_class(fields)
2167
2168 if not module:
2169 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2170 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2171 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2172 self.block.signatures.append(self.function)
2173 self.next(self.state_parameters_start)
2174
2175 # Now entering the parameters section. The rules, formally stated:
2176 #
2177 # * All lines must be indented with spaces only.
2178 # * The first line must be a parameter declaration.
2179 # * The first line must be indented.
2180 # * This first line establishes the indent for parameters.
2181 # * We'll call this number of spaces P (for "parameter").
2182 # * Thenceforth:
2183 # * Lines indented with P spaces specify a parameter.
2184 # * Lines indented with > P spaces are docstrings for the previous
2185 # parameter.
2186 # * We'll call this number of spaces D (for "docstring").
2187 # * All subsequent lines indented with >= D spaces are stored as
2188 # part of the per-parameter docstring.
2189 # * All lines will have the first D spaces of the indent stripped
2190 # before they are stored.
2191 # * It's illegal to have a line starting with a number of spaces X
2192 # such that P < X < D.
2193 # * A line with < P spaces is the first line of the function
2194 # docstring, which ends processing for parameters and per-parameter
2195 # docstrings.
2196 # * The first line of the function docstring must be at the same
2197 # indent as the function declaration.
2198 # * It's illegal to have any line in the parameters section starting
2199 # with X spaces such that F < X < P. (As before, F is the indent
2200 # of the function declaration.)
2201 #
2202 ##############
2203 #
2204 # Also, currently Argument Clinic places the following restrictions on groups:
2205 # * Each group must contain at least one parameter.
2206 # * Each group may contain at most one group, which must be the furthest
2207 # thing in the group from the required parameters. (The nested group
2208 # must be the first in the group when it's before the required
2209 # parameters, and the last thing in the group when after the required
2210 # parameters.)
2211 # * There may be at most one (top-level) group to the left or right of
2212 # the required parameters.
2213 # * You must specify a slash, and it must be after all parameters.
2214 # (In other words: either all parameters are positional-only,
2215 # or none are.)
2216 #
2217 # Said another way:
2218 # * Each group must contain at least one parameter.
2219 # * All left square brackets before the required parameters must be
2220 # consecutive. (You can't have a left square bracket followed
2221 # by a parameter, then another left square bracket. You can't
2222 # have a left square bracket, a parameter, a right square bracket,
2223 # and then a left square bracket.)
2224 # * All right square brackets after the required parameters must be
2225 # consecutive.
2226 #
2227 # These rules are enforced with a single state variable:
2228 # "parameter_state". (Previously the code was a miasma of ifs and
2229 # separate boolean state variables.) The states are:
2230 #
2231 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2232 # 01 2 3 4 5 6 <- state transitions
2233 #
2234 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2235 # 1: ps_left_square_before. left square brackets before required parameters.
2236 # 2: ps_group_before. in a group, before required parameters.
2237 # 3: ps_required. required parameters. (renumber left groups!)
2238 # 4: ps_group_after. in a group, after required parameters.
2239 # 5: ps_right_square_after. right square brackets after required parameters.
2240 # 6: ps_seen_slash. seen slash.
2241 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2242 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2243
2244 def state_parameters_start(self, line):
2245 if self.ignore_line(line):
2246 return
2247
2248 # if this line is not indented, we have no parameters
2249 if not self.indent.infer(line):
2250 return self.next(self.state_function_docstring, line)
2251
2252 return self.next(self.state_parameter, line)
2253
2254
2255 def to_required(self):
2256 """
2257 Transition to the "required" parameter state.
2258 """
2259 if self.parameter_state != self.ps_required:
2260 self.parameter_state = self.ps_required
2261 for p in self.function.parameters.values():
2262 p.group = -p.group
2263
2264 def state_parameter(self, line):
2265 if self.ignore_line(line):
2266 return
2267
2268 assert self.indent.depth == 2
2269 indent = self.indent.infer(line)
2270 if indent == -1:
2271 # we outdented, must be to definition column
2272 return self.next(self.state_function_docstring, line)
2273
2274 if indent == 1:
2275 # we indented, must be to new parameter docstring column
2276 return self.next(self.state_parameter_docstring_start, line)
2277
2278 line = line.lstrip()
2279
2280 if line in ('*', '/', '[', ']'):
2281 self.parse_special_symbol(line)
2282 return
2283
2284 if self.parameter_state in (self.ps_start, self.ps_required):
2285 self.to_required()
2286 elif self.parameter_state == self.ps_left_square_before:
2287 self.parameter_state = self.ps_group_before
2288 elif self.parameter_state == self.ps_group_before:
2289 if not self.group:
2290 self.to_required()
2291 elif self.parameter_state == self.ps_group_after:
2292 pass
2293 else:
2294 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2295
2296 ast_input = "def x({}): pass".format(line)
2297 module = None
2298 try:
2299 module = ast.parse(ast_input)
2300 except SyntaxError:
2301 pass
2302 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07002303 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07002304
2305 function_args = module.body[0].args
2306 parameter = function_args.args[0]
2307
2308 if function_args.defaults:
2309 expr = function_args.defaults[0]
2310 # mild hack: explicitly support NULL as a default value
2311 if isinstance(expr, ast.Name) and expr.id == 'NULL':
2312 value = NULL
2313 else:
2314 value = ast.literal_eval(expr)
2315 else:
2316 value = unspecified
2317
2318 parameter_name = parameter.arg
2319 name, legacy, kwargs = self.parse_converter(parameter.annotation)
2320 dict = legacy_converters if legacy else converters
2321 legacy_str = "legacy " if legacy else ""
2322 if name not in dict:
2323 fail('{} is not a valid {}converter'.format(name, legacy_str))
2324 converter = dict[name](parameter_name, self.function, value, **kwargs)
2325
Larry Hastingsebdcb502013-11-23 14:54:00 -08002326 # special case: if it's the self converter,
2327 # don't actually add it to the parameter list
2328 if isinstance(converter, self_converter):
2329 if self.function.parameters or (self.parameter_state != self.ps_required):
2330 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
2331 if self.function.self_converter:
2332 fail("You can't specify the 'self' parameter more than once.")
2333 self.function.self_converter = converter
2334 self.parameter_state = self.ps_start
2335 return
2336
Larry Hastings31826802013-10-19 00:09:25 -07002337 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
2338 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
2339 self.function.parameters[parameter_name] = p
2340
2341 def parse_converter(self, annotation):
2342 if isinstance(annotation, ast.Str):
2343 return annotation.s, True, {}
2344
2345 if isinstance(annotation, ast.Name):
2346 return annotation.id, False, {}
2347
2348 assert isinstance(annotation, ast.Call)
2349
2350 name = annotation.func.id
2351 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
2352 return name, False, kwargs
2353
2354 def parse_special_symbol(self, symbol):
2355 if self.parameter_state == self.ps_seen_slash:
2356 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
2357
2358 if symbol == '*':
2359 if self.keyword_only:
2360 fail("Function " + self.function.name + " uses '*' more than once.")
2361 self.keyword_only = True
2362 elif symbol == '[':
2363 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
2364 self.parameter_state = self.ps_left_square_before
2365 elif self.parameter_state in (self.ps_required, self.ps_group_after):
2366 self.parameter_state = self.ps_group_after
2367 else:
2368 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2369 self.group += 1
2370 elif symbol == ']':
2371 if not self.group:
2372 fail("Function " + self.function.name + " has a ] without a matching [.")
2373 if not any(p.group == self.group for p in self.function.parameters.values()):
2374 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
2375 self.group -= 1
2376 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
2377 self.parameter_state = self.ps_group_before
2378 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
2379 self.parameter_state = self.ps_right_square_after
2380 else:
2381 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2382 elif symbol == '/':
2383 # ps_required is allowed here, that allows positional-only without option groups
2384 # to work (and have default values!)
2385 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
2386 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2387 if self.keyword_only:
2388 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2389 self.parameter_state = self.ps_seen_slash
2390 # fixup preceeding parameters
2391 for p in self.function.parameters.values():
2392 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
2393 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2394 p.kind = inspect.Parameter.POSITIONAL_ONLY
2395
2396 def state_parameter_docstring_start(self, line):
2397 self.parameter_docstring_indent = len(self.indent.margin)
2398 assert self.indent.depth == 3
2399 return self.next(self.state_parameter_docstring, line)
2400
2401 # every line of the docstring must start with at least F spaces,
2402 # where F > P.
2403 # these F spaces will be stripped.
2404 def state_parameter_docstring(self, line):
2405 stripped = line.strip()
2406 if stripped.startswith('#'):
2407 return
2408
2409 indent = self.indent.measure(line)
2410 if indent < self.parameter_docstring_indent:
2411 self.indent.infer(line)
2412 assert self.indent.depth < 3
2413 if self.indent.depth == 2:
2414 # back to a parameter
2415 return self.next(self.state_parameter, line)
2416 assert self.indent.depth == 1
2417 return self.next(self.state_function_docstring, line)
2418
2419 assert self.function.parameters
2420 last_parameter = next(reversed(list(self.function.parameters.values())))
2421
2422 new_docstring = last_parameter.docstring
2423
2424 if new_docstring:
2425 new_docstring += '\n'
2426 if stripped:
2427 new_docstring += self.indent.dedent(line)
2428
2429 last_parameter.docstring = new_docstring
2430
2431 # the final stanza of the DSL is the docstring.
2432 def state_function_docstring(self, line):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002433 if not self.function.self_converter:
2434 self.function.self_converter = self_converter("self", self.function)
2435
Larry Hastings31826802013-10-19 00:09:25 -07002436 if self.group:
2437 fail("Function " + self.function.name + " has a ] without a matching [.")
2438
2439 stripped = line.strip()
2440 if stripped.startswith('#'):
2441 return
2442
2443 new_docstring = self.function.docstring
2444 if new_docstring:
2445 new_docstring += "\n"
2446 if stripped:
2447 line = self.indent.dedent(line).rstrip()
2448 else:
2449 line = ''
2450 new_docstring += line
2451 self.function.docstring = new_docstring
2452
2453 def format_docstring(self):
2454 f = self.function
2455
2456 add, output = text_accumulator()
2457 parameters = list(f.parameters.values())
2458
2459 ##
2460 ## docstring first line
2461 ##
2462
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002463 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07002464 add('(')
2465
2466 # populate "right_bracket_count" field for every parameter
2467 if parameters:
2468 # for now, the only way Clinic supports positional-only parameters
2469 # is if all of them are positional-only.
2470 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
2471 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
2472 assert all(positional_only_parameters)
2473 for p in parameters:
2474 p.right_bracket_count = abs(p.group)
2475 else:
2476 # don't put any right brackets around non-positional-only parameters, ever.
2477 for p in parameters:
2478 p.right_bracket_count = 0
2479
2480 right_bracket_count = 0
2481
2482 def fix_right_bracket_count(desired):
2483 nonlocal right_bracket_count
2484 s = ''
2485 while right_bracket_count < desired:
2486 s += '['
2487 right_bracket_count += 1
2488 while right_bracket_count > desired:
2489 s += ']'
2490 right_bracket_count -= 1
2491 return s
2492
2493 added_star = False
2494 add_comma = False
2495
2496 for p in parameters:
2497 assert p.name
2498
2499 if p.is_keyword_only() and not added_star:
2500 added_star = True
2501 if add_comma:
2502 add(', ')
2503 add('*')
2504
2505 a = [p.name]
2506 if p.converter.is_optional():
2507 a.append('=')
2508 value = p.converter.default
2509 a.append(p.converter.doc_default)
2510 s = fix_right_bracket_count(p.right_bracket_count)
2511 s += "".join(a)
2512 if add_comma:
2513 add(', ')
2514 add(s)
2515 add_comma = True
2516
2517 add(fix_right_bracket_count(0))
2518 add(')')
2519
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002520 # if f.return_converter.doc_default:
2521 # add(' -> ')
2522 # add(f.return_converter.doc_default)
Larry Hastings31826802013-10-19 00:09:25 -07002523
2524 docstring_first_line = output()
2525
2526 # now fix up the places where the brackets look wrong
2527 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
2528
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002529 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07002530 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002531 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07002532 for p in parameters:
2533 if not p.docstring.strip():
2534 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002535 if spacer_line:
2536 add('\n')
2537 else:
2538 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07002539 add(" ")
2540 add(p.name)
2541 add('\n')
2542 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002543 parameters = output()
2544 if parameters:
2545 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07002546
2547 ##
2548 ## docstring body
2549 ##
2550
2551 docstring = f.docstring.rstrip()
2552 lines = [line.rstrip() for line in docstring.split('\n')]
2553
2554 # Enforce the summary line!
2555 # The first line of a docstring should be a summary of the function.
2556 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
2557 # by itself.
2558 #
2559 # Argument Clinic enforces the following rule:
2560 # * either the docstring is empty,
2561 # * or it must have a summary line.
2562 #
2563 # Guido said Clinic should enforce this:
2564 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
2565
2566 if len(lines) >= 2:
2567 if lines[1]:
2568 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
2569 "Every non-blank function docstring must start with\n" +
2570 "a single line summary followed by an empty line.")
2571 elif len(lines) == 1:
2572 # the docstring is only one line right now--the summary line.
2573 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002574 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07002575 lines.append('')
2576
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002577 parameters_marker_count = len(docstring.split('{parameters}')) - 1
2578 if parameters_marker_count > 1:
2579 fail('You may not specify {parameters} more than once in a docstring!')
2580
2581 if not parameters_marker_count:
2582 # insert after summary line
2583 lines.insert(2, '{parameters}')
2584
2585 # insert at front of docstring
2586 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07002587
2588 docstring = "\n".join(lines)
2589
2590 add(docstring)
2591 docstring = output()
2592
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002593 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07002594 docstring = docstring.rstrip()
2595
2596 return docstring
2597
2598 def state_terminal(self, line):
2599 """
2600 Called when processing the block is done.
2601 """
2602 assert not line
2603
2604 if not self.function:
2605 return
2606
2607 if self.keyword_only:
2608 values = self.function.parameters.values()
2609 if not values:
2610 no_parameter_after_star = True
2611 else:
2612 last_parameter = next(reversed(list(values)))
2613 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
2614 if no_parameter_after_star:
2615 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
2616
2617 # remove trailing whitespace from all parameter docstrings
2618 for name, value in self.function.parameters.items():
2619 if not value:
2620 continue
2621 value.docstring = value.docstring.rstrip()
2622
2623 self.function.docstring = self.format_docstring()
2624
2625
2626# maps strings to callables.
2627# the callable should return an object
2628# that implements the clinic parser
2629# interface (__init__ and parse).
2630#
2631# example parsers:
2632# "clinic", handles the Clinic DSL
2633# "python", handles running Python code
2634#
2635parsers = {'clinic' : DSLParser, 'python': PythonParser}
2636
2637
2638clinic = None
2639
2640
2641def main(argv):
2642 import sys
2643
2644 if sys.version_info.major < 3 or sys.version_info.minor < 3:
2645 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
2646
2647 import argparse
2648 cmdline = argparse.ArgumentParser()
2649 cmdline.add_argument("-f", "--force", action='store_true')
2650 cmdline.add_argument("-o", "--output", type=str)
2651 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002652 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07002653 cmdline.add_argument("filename", type=str, nargs="*")
2654 ns = cmdline.parse_args(argv)
2655
2656 if ns.converters:
2657 if ns.filename:
2658 print("Usage error: can't specify --converters and a filename at the same time.")
2659 print()
2660 cmdline.print_usage()
2661 sys.exit(-1)
2662 converters = []
2663 return_converters = []
2664 ignored = set("""
2665 add_c_converter
2666 add_c_return_converter
2667 add_default_legacy_c_converter
2668 add_legacy_c_converter
2669 """.strip().split())
2670 module = globals()
2671 for name in module:
2672 for suffix, ids in (
2673 ("_return_converter", return_converters),
2674 ("_converter", converters),
2675 ):
2676 if name in ignored:
2677 continue
2678 if name.endswith(suffix):
2679 ids.append((name, name[:-len(suffix)]))
2680 break
2681 print()
2682
2683 print("Legacy converters:")
2684 legacy = sorted(legacy_converters)
2685 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
2686 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
2687 print()
2688
2689 for title, attribute, ids in (
2690 ("Converters", 'converter_init', converters),
2691 ("Return converters", 'return_converter_init', return_converters),
2692 ):
2693 print(title + ":")
2694 longest = -1
2695 for name, short_name in ids:
2696 longest = max(longest, len(short_name))
2697 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
2698 cls = module[name]
2699 callable = getattr(cls, attribute, None)
2700 if not callable:
2701 continue
2702 signature = inspect.signature(callable)
2703 parameters = []
2704 for parameter_name, parameter in signature.parameters.items():
2705 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2706 if parameter.default != inspect.Parameter.empty:
2707 s = '{}={!r}'.format(parameter_name, parameter.default)
2708 else:
2709 s = parameter_name
2710 parameters.append(s)
2711 print(' {}({})'.format(short_name, ', '.join(parameters)))
2712 # add_comma = False
2713 # for parameter_name, parameter in signature.parameters.items():
2714 # if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2715 # if add_comma:
2716 # parameters.append(', ')
2717 # else:
2718 # add_comma = True
2719 # s = parameter_name
2720 # if parameter.default != inspect.Parameter.empty:
2721 # s += '=' + repr(parameter.default)
2722 # parameters.append(s)
2723 # parameters.append(')')
2724
2725 # print(" ", short_name + "".join(parameters))
2726 print()
Larry Hastings78cf85c2014-01-04 12:44:57 -08002727 print("All converters also accept (doc_default=None, required=False, annotation=None).")
Larry Hastings31826802013-10-19 00:09:25 -07002728 print("All return converters also accept (doc_default=None).")
2729 sys.exit(0)
2730
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002731 if ns.make:
2732 if ns.output or ns.filename:
2733 print("Usage error: can't use -o or filenames with --make.")
2734 print()
2735 cmdline.print_usage()
2736 sys.exit(-1)
2737 for root, dirs, files in os.walk('.'):
2738 for rcs_dir in ('.svn', '.git', '.hg'):
2739 if rcs_dir in dirs:
2740 dirs.remove(rcs_dir)
2741 for filename in files:
2742 if not filename.endswith('.c'):
2743 continue
2744 path = os.path.join(root, filename)
2745 parse_file(path, verify=not ns.force)
2746 return
2747
Larry Hastings31826802013-10-19 00:09:25 -07002748 if not ns.filename:
2749 cmdline.print_usage()
2750 sys.exit(-1)
2751
2752 if ns.output and len(ns.filename) > 1:
2753 print("Usage error: can't use -o with multiple filenames.")
2754 print()
2755 cmdline.print_usage()
2756 sys.exit(-1)
2757
2758 for filename in ns.filename:
2759 parse_file(filename, output=ns.output, verify=not ns.force)
2760
2761
2762if __name__ == "__main__":
2763 sys.exit(main(sys.argv[1:]))