blob: 44456a7cdb984c5bad9951cd6b4d0a89b34f5699 [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 }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001000extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1001extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001002
1003
1004# maps strings to callables.
1005# these callables must be of the form:
1006# def foo(name, default, *, ...)
1007# The callable may have any number of keyword-only parameters.
1008# The callable must return a CConverter object.
1009# The callable should not call builtins.print.
1010converters = {}
1011
1012# maps strings to callables.
1013# these callables follow the same rules as those for "converters" above.
1014# note however that they will never be called with keyword-only parameters.
1015legacy_converters = {}
1016
1017
1018# maps strings to callables.
1019# these callables must be of the form:
1020# def foo(*, ...)
1021# The callable may have any number of keyword-only parameters.
1022# The callable must return a CConverter object.
1023# The callable should not call builtins.print.
1024return_converters = {}
1025
1026class Clinic:
1027 def __init__(self, language, printer=None, *, verify=True, filename=None):
1028 # maps strings to Parser objects.
1029 # (instantiated from the "parsers" global.)
1030 self.parsers = {}
1031 self.language = language
1032 self.printer = printer or BlockPrinter(language)
1033 self.verify = verify
1034 self.filename = filename
1035 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001036 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -07001037
1038 global clinic
1039 clinic = self
1040
1041 def parse(self, input):
1042 printer = self.printer
1043 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1044 for block in self.block_parser:
1045 dsl_name = block.dsl_name
1046 if dsl_name:
1047 if dsl_name not in self.parsers:
1048 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1049 self.parsers[dsl_name] = parsers[dsl_name](self)
1050 parser = self.parsers[dsl_name]
1051 parser.parse(block)
1052 printer.print_block(block)
1053 return printer.f.getvalue()
1054
1055 def _module_and_class(self, fields):
1056 """
1057 fields should be an iterable of field names.
1058 returns a tuple of (module, class).
1059 the module object could actually be self (a clinic object).
1060 this function is only ever used to find the parent of where
1061 a new class/module should go.
1062 """
1063 in_classes = False
1064 parent = module = self
1065 cls = None
1066 so_far = []
1067
1068 for field in fields:
1069 so_far.append(field)
1070 if not in_classes:
1071 child = parent.modules.get(field)
1072 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001073 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001074 continue
1075 in_classes = True
1076 if not hasattr(parent, 'classes'):
1077 return module, cls
1078 child = parent.classes.get(field)
1079 if not child:
1080 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1081 cls = parent = child
1082
1083 return module, cls
1084
1085
1086def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1087 extension = os.path.splitext(filename)[1][1:]
1088 if not extension:
1089 fail("Can't extract file type for file " + repr(filename))
1090
1091 try:
1092 language = extensions[extension]()
1093 except KeyError:
1094 fail("Can't identify file type for file " + repr(filename))
1095
1096 clinic = Clinic(language, verify=verify, filename=filename)
1097
1098 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001099 raw = f.read()
1100
1101 cooked = clinic.parse(raw)
1102 if cooked == raw:
1103 return
Larry Hastings31826802013-10-19 00:09:25 -07001104
1105 directory = os.path.dirname(filename) or '.'
1106
1107 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001108 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001109 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1110 with open(tmpfilename, "wb") as f:
1111 f.write(bytes)
1112 os.replace(tmpfilename, output or filename)
1113
1114
1115def compute_checksum(input):
1116 input = input or ''
1117 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1118
1119
1120
1121
1122class PythonParser:
1123 def __init__(self, clinic):
1124 pass
1125
1126 def parse(self, block):
1127 s = io.StringIO()
1128 with OverrideStdioWith(s):
1129 exec(block.input)
1130 block.output = s.getvalue()
1131
1132
1133class Module:
1134 def __init__(self, name, module=None):
1135 self.name = name
1136 self.module = self.parent = module
1137
1138 self.modules = collections.OrderedDict()
1139 self.classes = collections.OrderedDict()
1140 self.functions = []
1141
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001142 def __repr__(self):
1143 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1144
Larry Hastings31826802013-10-19 00:09:25 -07001145class Class:
1146 def __init__(self, name, module=None, cls=None):
1147 self.name = name
1148 self.module = module
1149 self.cls = cls
1150 self.parent = cls or module
1151
1152 self.classes = collections.OrderedDict()
1153 self.functions = []
1154
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001155 def __repr__(self):
1156 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1157
1158
Larry Hastings31826802013-10-19 00:09:25 -07001159DATA, CALLABLE, METHOD, STATIC_METHOD, CLASS_METHOD = range(5)
1160
1161class Function:
1162 """
1163 Mutable duck type for inspect.Function.
1164
1165 docstring - a str containing
1166 * embedded line breaks
1167 * text outdented to the left margin
1168 * no trailing whitespace.
1169 It will always be true that
1170 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1171 """
1172
1173 def __init__(self, parameters=None, *, name,
1174 module, cls=None, c_basename=None,
1175 full_name=None,
1176 return_converter, return_annotation=_empty,
1177 docstring=None, kind=CALLABLE, coexist=False):
1178 self.parameters = parameters or collections.OrderedDict()
1179 self.return_annotation = return_annotation
1180 self.name = name
1181 self.full_name = full_name
1182 self.module = module
1183 self.cls = cls
1184 self.parent = cls or module
1185 self.c_basename = c_basename
1186 self.return_converter = return_converter
1187 self.docstring = docstring or ''
1188 self.kind = kind
1189 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001190 self.self_converter = None
1191
1192 @property
1193 def methoddef_flags(self):
1194 flags = []
1195 if self.kind == CLASS_METHOD:
1196 flags.append('METH_CLASS')
1197 elif self.kind == STATIC_METHOD:
1198 flags.append('METH_STATIC')
1199 else:
1200 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1201 if self.coexist:
1202 flags.append('METH_COEXIST')
1203 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001204
1205 def __repr__(self):
1206 return '<clinic.Function ' + self.name + '>'
1207
1208
1209class Parameter:
1210 """
1211 Mutable duck type of inspect.Parameter.
1212 """
1213
1214 def __init__(self, name, kind, *, default=_empty,
1215 function, converter, annotation=_empty,
1216 docstring=None, group=0):
1217 self.name = name
1218 self.kind = kind
1219 self.default = default
1220 self.function = function
1221 self.converter = converter
1222 self.annotation = annotation
1223 self.docstring = docstring or ''
1224 self.group = group
1225
1226 def __repr__(self):
1227 return '<clinic.Parameter ' + self.name + '>'
1228
1229 def is_keyword_only(self):
1230 return self.kind == inspect.Parameter.KEYWORD_ONLY
1231
1232py_special_values = {
1233 NULL: "None",
1234}
1235
1236def py_repr(o):
1237 special = py_special_values.get(o)
1238 if special:
1239 return special
1240 return repr(o)
1241
1242
1243c_special_values = {
1244 NULL: "NULL",
1245 None: "Py_None",
1246}
1247
1248def c_repr(o):
1249 special = c_special_values.get(o)
1250 if special:
1251 return special
1252 if isinstance(o, str):
1253 return '"' + quoted_for_c_string(o) + '"'
1254 return repr(o)
1255
1256def add_c_converter(f, name=None):
1257 if not name:
1258 name = f.__name__
1259 if not name.endswith('_converter'):
1260 return f
1261 name = name[:-len('_converter')]
1262 converters[name] = f
1263 return f
1264
1265def add_default_legacy_c_converter(cls):
1266 # automatically add converter for default format unit
1267 # (but without stomping on the existing one if it's already
1268 # set, in case you subclass)
1269 if ((cls.format_unit != 'O&') and
1270 (cls.format_unit not in legacy_converters)):
1271 legacy_converters[cls.format_unit] = cls
1272 return cls
1273
1274def add_legacy_c_converter(format_unit, **kwargs):
1275 """
1276 Adds a legacy converter.
1277 """
1278 def closure(f):
1279 if not kwargs:
1280 added_f = f
1281 else:
1282 added_f = functools.partial(f, **kwargs)
1283 legacy_converters[format_unit] = added_f
1284 return f
1285 return closure
1286
1287class CConverterAutoRegister(type):
1288 def __init__(cls, name, bases, classdict):
1289 add_c_converter(cls)
1290 add_default_legacy_c_converter(cls)
1291
1292class CConverter(metaclass=CConverterAutoRegister):
1293 """
1294 For the init function, self, name, function, and default
1295 must be keyword-or-positional parameters. All other
1296 parameters (including "required" and "doc_default")
1297 must be keyword-only.
1298 """
1299
Larry Hastings78cf85c2014-01-04 12:44:57 -08001300 # The C type to use for this variable.
1301 # 'type' should be a Python string specifying the type, e.g. "int".
1302 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001303 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001304
1305 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001306 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001307 default = unspecified
1308
Larry Hastings31826802013-10-19 00:09:25 -07001309 # "default" as it should appear in the documentation, as a string.
1310 # Or None if there is no default.
1311 doc_default = None
1312
Larry Hastingsabc716b2013-11-20 09:13:52 -08001313 # "default" converted into a str for rendering into Python code.
1314 py_default = None
1315
Larry Hastings31826802013-10-19 00:09:25 -07001316 # "default" converted into a C value, as a string.
1317 # Or None if there is no default.
1318 c_default = None
1319
Larry Hastingsabc716b2013-11-20 09:13:52 -08001320 # The default value used to initialize the C variable when
1321 # there is no default, but not specifying a default may
1322 # result in an "uninitialized variable" warning. This can
1323 # easily happen when using option groups--although
1324 # properly-written code won't actually use the variable,
1325 # the variable does get passed in to the _impl. (Ah, if
1326 # only dataflow analysis could inline the static function!)
1327 #
1328 # This value is specified as a string.
1329 # Every non-abstract subclass should supply a valid value.
1330 c_ignored_default = 'NULL'
1331
Larry Hastings31826802013-10-19 00:09:25 -07001332 # The C converter *function* to be used, if any.
1333 # (If this is not None, format_unit must be 'O&'.)
1334 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001335
Larry Hastings78cf85c2014-01-04 12:44:57 -08001336 # Should Argument Clinic add a '&' before the name of
1337 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001338 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001339
1340 # Should Argument Clinic add a '&' before the name of
1341 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001342 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001343
1344 #############################################################
1345 #############################################################
1346 ## You shouldn't need to read anything below this point to ##
1347 ## write your own converter functions. ##
1348 #############################################################
1349 #############################################################
1350
1351 # The "format unit" to specify for this variable when
1352 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1353 # Custom converters should always use the default value of 'O&'.
1354 format_unit = 'O&'
1355
1356 # What encoding do we want for this variable? Only used
1357 # by format units starting with 'e'.
1358 encoding = None
1359
1360 # Do we want an adjacent '_length' variable for this variable?
1361 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001362 length = False
1363
1364 def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs):
1365 self.function = function
1366 self.name = name
1367
1368 if default is not unspecified:
1369 self.default = default
1370 self.py_default = py_repr(default)
1371 self.doc_default = doc_default if doc_default is not None else self.py_default
1372 self.c_default = c_repr(default)
1373 elif doc_default is not None:
1374 fail(function.fullname + " argument " + name + " specified a 'doc_default' without having a 'default'")
1375 if annotation != unspecified:
1376 fail("The 'annotation' parameter is not currently permitted.")
1377 self.required = required
1378 self.converter_init(**kwargs)
1379
1380 def converter_init(self):
1381 pass
1382
1383 def is_optional(self):
1384 return (self.default is not unspecified) and (not self.required)
1385
1386 def render(self, parameter, data):
1387 """
1388 parameter is a clinic.Parameter instance.
1389 data is a CRenderData instance.
1390 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001391 self.parameter = parameter
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001392 name = ensure_legal_c_identifier(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07001393
1394 # declarations
1395 d = self.declaration()
1396 data.declarations.append(d)
1397
1398 # initializers
1399 initializers = self.initialize()
1400 if initializers:
1401 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1402
1403 # impl_arguments
1404 s = ("&" if self.impl_by_reference else "") + name
1405 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001406 if self.length:
1407 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001408
1409 # keywords
1410 data.keywords.append(name)
1411
1412 # format_units
1413 if self.is_optional() and '|' not in data.format_units:
1414 data.format_units.append('|')
1415 if parameter.is_keyword_only() and '$' not in data.format_units:
1416 data.format_units.append('$')
1417 data.format_units.append(self.format_unit)
1418
1419 # parse_arguments
1420 self.parse_argument(data.parse_arguments)
1421
1422 # impl_parameters
1423 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001424 if self.length:
1425 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001426
1427 # cleanup
1428 cleanup = self.cleanup()
1429 if cleanup:
1430 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1431
Larry Hastingsebdcb502013-11-23 14:54:00 -08001432 def length_name(self):
1433 """Computes the name of the associated "length" variable."""
1434 if not self.length:
1435 return None
1436 return ensure_legal_c_identifier(self.name) + "_length"
1437
Larry Hastings31826802013-10-19 00:09:25 -07001438 # Why is this one broken out separately?
1439 # For "positional-only" function parsing,
1440 # which generates a bunch of PyArg_ParseTuple calls.
1441 def parse_argument(self, list):
1442 assert not (self.converter and self.encoding)
1443 if self.format_unit == 'O&':
1444 assert self.converter
1445 list.append(self.converter)
1446
1447 if self.encoding:
1448 list.append(self.encoding)
1449
Larry Hastingsebdcb502013-11-23 14:54:00 -08001450 legal_name = ensure_legal_c_identifier(self.name)
1451 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001452 list.append(s)
1453
Larry Hastingsebdcb502013-11-23 14:54:00 -08001454 if self.length:
1455 list.append("&" + self.length_name())
1456
Larry Hastings31826802013-10-19 00:09:25 -07001457 #
1458 # All the functions after here are intended as extension points.
1459 #
1460
1461 def simple_declaration(self, by_reference=False):
1462 """
1463 Computes the basic declaration of the variable.
1464 Used in computing the prototype declaration and the
1465 variable declaration.
1466 """
1467 prototype = [self.type]
1468 if by_reference or not self.type.endswith('*'):
1469 prototype.append(" ")
1470 if by_reference:
1471 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001472 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001473 return "".join(prototype)
1474
1475 def declaration(self):
1476 """
1477 The C statement to declare this variable.
1478 """
1479 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08001480 default = self.c_default
1481 if not default and self.parameter.group:
1482 default = self.c_ignored_default
1483 if default:
Larry Hastings31826802013-10-19 00:09:25 -07001484 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08001485 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07001486 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001487 if self.length:
1488 declaration.append('\nPy_ssize_clean_t ')
1489 declaration.append(self.length_name())
1490 declaration.append(';')
Larry Hastings31826802013-10-19 00:09:25 -07001491 return "".join(declaration)
1492
1493 def initialize(self):
1494 """
1495 The C statements required to set up this variable before parsing.
1496 Returns a string containing this code indented at column 0.
1497 If no initialization is necessary, returns an empty string.
1498 """
1499 return ""
1500
1501 def cleanup(self):
1502 """
1503 The C statements required to clean up after this variable.
1504 Returns a string containing this code indented at column 0.
1505 If no cleanup is necessary, returns an empty string.
1506 """
1507 return ""
1508
1509
1510class bool_converter(CConverter):
1511 type = 'int'
1512 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001513 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07001514
1515 def converter_init(self):
1516 self.default = bool(self.default)
1517 self.c_default = str(int(self.default))
1518
1519class char_converter(CConverter):
1520 type = 'char'
1521 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001522 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001523
1524@add_legacy_c_converter('B', bitwise=True)
1525class byte_converter(CConverter):
1526 type = 'byte'
1527 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001528 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001529
1530 def converter_init(self, *, bitwise=False):
1531 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001532 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07001533
1534class short_converter(CConverter):
1535 type = 'short'
1536 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001537 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001538
1539class unsigned_short_converter(CConverter):
1540 type = 'unsigned short'
1541 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001542 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001543
1544 def converter_init(self, *, bitwise=False):
1545 if not bitwise:
1546 fail("Unsigned shorts must be bitwise (for now).")
1547
Larry Hastingsebdcb502013-11-23 14:54:00 -08001548@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07001549class int_converter(CConverter):
1550 type = 'int'
1551 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001552 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001553
Larry Hastingsebdcb502013-11-23 14:54:00 -08001554 def converter_init(self, *, types='int'):
1555 if types == 'str':
1556 self.format_unit = 'C'
1557 elif types != 'int':
1558 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07001559
1560class unsigned_int_converter(CConverter):
1561 type = 'unsigned int'
1562 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001563 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001564
1565 def converter_init(self, *, bitwise=False):
1566 if not bitwise:
1567 fail("Unsigned ints must be bitwise (for now).")
1568
1569class long_converter(CConverter):
1570 type = 'long'
1571 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001572 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001573
1574class unsigned_long_converter(CConverter):
1575 type = 'unsigned long'
1576 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001577 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001578
1579 def converter_init(self, *, bitwise=False):
1580 if not bitwise:
1581 fail("Unsigned longs must be bitwise (for now).")
1582
1583class PY_LONG_LONG_converter(CConverter):
1584 type = 'PY_LONG_LONG'
1585 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001586 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001587
1588class unsigned_PY_LONG_LONG_converter(CConverter):
1589 type = 'unsigned PY_LONG_LONG'
1590 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001591 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001592
1593 def converter_init(self, *, bitwise=False):
1594 if not bitwise:
1595 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
1596
1597class Py_ssize_t_converter(CConverter):
1598 type = 'Py_ssize_t'
1599 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001600 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001601
1602
1603class float_converter(CConverter):
1604 type = 'float'
1605 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001606 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001607
1608class double_converter(CConverter):
1609 type = 'double'
1610 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001611 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001612
1613
1614class Py_complex_converter(CConverter):
1615 type = 'Py_complex'
1616 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001617 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07001618
1619
1620class object_converter(CConverter):
1621 type = 'PyObject *'
1622 format_unit = 'O'
1623
1624 def converter_init(self, *, type=None):
1625 if type:
1626 assert isinstance(type, str)
1627 assert type.isidentifier()
1628 try:
1629 type = eval(type)
1630 # need more of these!
1631 type = {
1632 str: '&PyUnicode_Type',
1633 }[type]
1634 except NameError:
1635 type = type
1636 self.format_unit = 'O!'
1637 self.encoding = type
1638
1639
Larry Hastingsebdcb502013-11-23 14:54:00 -08001640@add_legacy_c_converter('s#', length=True)
1641@add_legacy_c_converter('y', type="bytes")
1642@add_legacy_c_converter('y#', type="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001643@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001644@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001645class str_converter(CConverter):
1646 type = 'const char *'
1647 format_unit = 's'
1648
Larry Hastingsebdcb502013-11-23 14:54:00 -08001649 def converter_init(self, *, encoding=None, types="str",
1650 length=False, nullable=False, zeroes=False):
1651
1652 types = set(types.strip().split())
1653 bytes_type = set(("bytes",))
1654 str_type = set(("str",))
1655 all_3_type = set(("bytearray",)) | bytes_type | str_type
1656 is_bytes = types == bytes_type
1657 is_str = types == str_type
1658 is_all_3 = types == all_3_type
1659
1660 self.length = bool(length)
1661 format_unit = None
1662
1663 if encoding:
1664 self.encoding = encoding
1665
1666 if is_str and not (length or zeroes or nullable):
1667 format_unit = 'es'
1668 elif is_all_3 and not (length or zeroes or nullable):
1669 format_unit = 'et'
1670 elif is_str and length and zeroes and not nullable:
1671 format_unit = 'es#'
1672 elif is_all_3 and length and not (nullable or zeroes):
1673 format_unit = 'et#'
1674
1675 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08001676 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001677 # TODO set pointer to NULL
1678 # TODO add cleanup for buffer
1679 pass
1680
1681 else:
1682 if zeroes:
1683 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
1684
1685 if is_bytes and not (nullable or length):
1686 format_unit = 'y'
1687 elif is_bytes and length and not nullable:
1688 format_unit = 'y#'
1689 elif is_str and not (nullable or length):
1690 format_unit = 's'
1691 elif is_str and length and not nullable:
1692 format_unit = 's#'
1693 elif is_str and nullable and not length:
1694 format_unit = 'z'
1695 elif is_str and nullable and length:
1696 format_unit = 'z#'
1697
1698 if not format_unit:
1699 fail("str_converter: illegal combination of arguments")
1700 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001701
1702
1703class PyBytesObject_converter(CConverter):
1704 type = 'PyBytesObject *'
1705 format_unit = 'S'
1706
1707class PyByteArrayObject_converter(CConverter):
1708 type = 'PyByteArrayObject *'
1709 format_unit = 'Y'
1710
1711class unicode_converter(CConverter):
1712 type = 'PyObject *'
1713 format_unit = 'U'
1714
Larry Hastingsebdcb502013-11-23 14:54:00 -08001715@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001716@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001717@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001718class Py_UNICODE_converter(CConverter):
1719 type = 'Py_UNICODE *'
1720 format_unit = 'u'
1721
Larry Hastingsebdcb502013-11-23 14:54:00 -08001722 def converter_init(self, *, nullable=False, length=False):
1723 format_unit = 'Z' if nullable else 'u'
1724 if length:
1725 format_unit += '#'
1726 self.length = True
1727 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001728
Larry Hastingsebdcb502013-11-23 14:54:00 -08001729#
1730# We define three string conventions for buffer types in the 'types' argument:
1731# 'buffer' : any object supporting the buffer interface
1732# 'rwbuffer': any object supporting the buffer interface, but must be writeable
1733# 'robuffer': any object supporting the buffer interface, but must not be writeable
1734#
1735@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
1736@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
1737@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07001738class Py_buffer_converter(CConverter):
1739 type = 'Py_buffer'
1740 format_unit = 'y*'
1741 impl_by_reference = True
Larry Hastingsabc716b2013-11-20 09:13:52 -08001742 c_ignored_default = "{NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07001743
Larry Hastingsebdcb502013-11-23 14:54:00 -08001744 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
1745 types = set(types.strip().split())
1746 bytes_type = set(('bytes',))
1747 bytearray_type = set(('bytearray',))
1748 buffer_type = set(('buffer',))
1749 rwbuffer_type = set(('rwbuffer',))
1750 robuffer_type = set(('robuffer',))
1751 str_type = set(('str',))
1752 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
1753
1754 format_unit = None
1755 if types == (str_type | bytes_bytearray_buffer_type):
1756 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07001757 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001758 if nullable:
1759 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
1760 elif types == (bytes_bytearray_buffer_type):
1761 format_unit = 'y*'
1762 elif types == (bytearray_type | rwuffer_type):
1763 format_unit = 'w*'
1764 if not format_unit:
1765 fail("Py_buffer_converter: illegal combination of arguments")
1766
1767 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001768
1769 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001770 name = ensure_legal_c_identifier(self.name)
1771 return "".join(["if (", name, ".buf)\n PyBuffer_Release(&", name, ");\n"])
1772
1773
1774class self_converter(CConverter):
1775 """
1776 A special-case converter:
1777 this is the default converter used for "self".
1778 """
1779 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08001780 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001781 f = self.function
1782 if f.kind == CALLABLE:
1783 if f.cls:
1784 self.name = "self"
1785 else:
1786 self.name = "module"
1787 self.type = "PyModuleDef *"
1788 elif f.kind == STATIC_METHOD:
1789 self.name = "null"
1790 self.type = "void *"
1791 elif f.kind == CLASS_METHOD:
1792 self.name = "cls"
1793 self.type = "PyTypeObject *"
1794
Larry Hastings78cf85c2014-01-04 12:44:57 -08001795 if type:
1796 self.type = type
1797
Larry Hastingsebdcb502013-11-23 14:54:00 -08001798 def render(self, parameter, data):
1799 fail("render() should never be called on self_converter instances")
1800
Larry Hastings31826802013-10-19 00:09:25 -07001801
1802
1803def add_c_return_converter(f, name=None):
1804 if not name:
1805 name = f.__name__
1806 if not name.endswith('_return_converter'):
1807 return f
1808 name = name[:-len('_return_converter')]
1809 return_converters[name] = f
1810 return f
1811
1812
1813class CReturnConverterAutoRegister(type):
1814 def __init__(cls, name, bases, classdict):
1815 add_c_return_converter(cls)
1816
1817class CReturnConverter(metaclass=CReturnConverterAutoRegister):
1818
Larry Hastings78cf85c2014-01-04 12:44:57 -08001819 # The C type to use for this variable.
1820 # 'type' should be a Python string specifying the type, e.g. "int".
1821 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001822 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08001823
1824 # The Python default value for this parameter, as a Python value.
1825 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001826 default = None
1827
1828 def __init__(self, *, doc_default=None, **kwargs):
1829 self.doc_default = doc_default
1830 try:
1831 self.return_converter_init(**kwargs)
1832 except TypeError as e:
1833 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
1834 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
1835
1836 def return_converter_init(self):
1837 pass
1838
1839 def declare(self, data, name="_return_value"):
1840 line = []
1841 add = line.append
1842 add(self.type)
1843 if not self.type.endswith('*'):
1844 add(' ')
1845 add(name + ';')
1846 data.declarations.append(''.join(line))
1847 data.return_value = name
1848
1849 def err_occurred_if(self, expr, data):
1850 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
1851
1852 def err_occurred_if_null_pointer(self, variable, data):
1853 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
1854
1855 def render(self, function, data):
1856 """
1857 function is a clinic.Function instance.
1858 data is a CRenderData instance.
1859 """
1860 pass
1861
1862add_c_return_converter(CReturnConverter, 'object')
1863
Larry Hastings78cf85c2014-01-04 12:44:57 -08001864class NoneType_return_converter(CReturnConverter):
1865 def render(self, function, data):
1866 self.declare(data)
1867 data.return_conversion.append('''
1868if (_return_value != Py_None)
1869 goto exit;
1870return_value = Py_None;
1871Py_INCREF(Py_None);
1872'''.strip())
1873
Larry Hastings31826802013-10-19 00:09:25 -07001874class int_return_converter(CReturnConverter):
1875 type = 'int'
1876
1877 def render(self, function, data):
1878 self.declare(data)
1879 self.err_occurred_if("_return_value == -1", data)
1880 data.return_conversion.append(
1881 'return_value = PyLong_FromLong((long)_return_value);\n')
1882
1883
1884class long_return_converter(CReturnConverter):
1885 type = 'long'
1886
1887 def render(self, function, data):
1888 self.declare(data)
1889 self.err_occurred_if("_return_value == -1", data)
1890 data.return_conversion.append(
1891 'return_value = PyLong_FromLong(_return_value);\n')
1892
1893
1894class Py_ssize_t_return_converter(CReturnConverter):
1895 type = 'Py_ssize_t'
1896
1897 def render(self, function, data):
1898 self.declare(data)
1899 self.err_occurred_if("_return_value == -1", data)
1900 data.return_conversion.append(
1901 'return_value = PyLong_FromSsize_t(_return_value);\n')
1902
1903
1904class DecodeFSDefault_return_converter(CReturnConverter):
1905 type = 'char *'
1906
1907 def render(self, function, data):
1908 self.declare(data)
1909 self.err_occurred_if_null_pointer("_return_value", data)
1910 data.return_conversion.append(
1911 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
1912
1913
1914class IndentStack:
1915 def __init__(self):
1916 self.indents = []
1917 self.margin = None
1918
1919 def _ensure(self):
1920 if not self.indents:
1921 fail('IndentStack expected indents, but none are defined.')
1922
1923 def measure(self, line):
1924 """
1925 Returns the length of the line's margin.
1926 """
1927 if '\t' in line:
1928 fail('Tab characters are illegal in the Clinic DSL.')
1929 stripped = line.lstrip()
1930 if not len(stripped):
1931 # we can't tell anything from an empty line
1932 # so just pretend it's indented like our current indent
1933 self._ensure()
1934 return self.indents[-1]
1935 return len(line) - len(stripped)
1936
1937 def infer(self, line):
1938 """
1939 Infer what is now the current margin based on this line.
1940 Returns:
1941 1 if we have indented (or this is the first margin)
1942 0 if the margin has not changed
1943 -N if we have dedented N times
1944 """
1945 indent = self.measure(line)
1946 margin = ' ' * indent
1947 if not self.indents:
1948 self.indents.append(indent)
1949 self.margin = margin
1950 return 1
1951 current = self.indents[-1]
1952 if indent == current:
1953 return 0
1954 if indent > current:
1955 self.indents.append(indent)
1956 self.margin = margin
1957 return 1
1958 # indent < current
1959 if indent not in self.indents:
1960 fail("Illegal outdent.")
1961 outdent_count = 0
1962 while indent != current:
1963 self.indents.pop()
1964 current = self.indents[-1]
1965 outdent_count -= 1
1966 self.margin = margin
1967 return outdent_count
1968
1969 @property
1970 def depth(self):
1971 """
1972 Returns how many margins are currently defined.
1973 """
1974 return len(self.indents)
1975
1976 def indent(self, line):
1977 """
1978 Indents a line by the currently defined margin.
1979 """
1980 return self.margin + line
1981
1982 def dedent(self, line):
1983 """
1984 Dedents a line by the currently defined margin.
1985 (The inverse of 'indent'.)
1986 """
1987 margin = self.margin
1988 indent = self.indents[-1]
1989 if not line.startswith(margin):
1990 fail('Cannot dedent, line does not start with the previous margin:')
1991 return line[indent:]
1992
1993
1994class DSLParser:
1995 def __init__(self, clinic):
1996 self.clinic = clinic
1997
1998 self.directives = {}
1999 for name in dir(self):
2000 # functions that start with directive_ are added to directives
2001 _, s, key = name.partition("directive_")
2002 if s:
2003 self.directives[key] = getattr(self, name)
2004
2005 # functions that start with at_ are too, with an @ in front
2006 _, s, key = name.partition("at_")
2007 if s:
2008 self.directives['@' + key] = getattr(self, name)
2009
2010 self.reset()
2011
2012 def reset(self):
2013 self.function = None
2014 self.state = self.state_dsl_start
2015 self.parameter_indent = None
2016 self.keyword_only = False
2017 self.group = 0
2018 self.parameter_state = self.ps_start
2019 self.indent = IndentStack()
2020 self.kind = CALLABLE
2021 self.coexist = False
2022
Larry Hastingsebdcb502013-11-23 14:54:00 -08002023 def directive_version(self, required):
2024 global version
2025 if version_comparitor(version, required) < 0:
2026 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2027
Larry Hastings31826802013-10-19 00:09:25 -07002028 def directive_module(self, name):
2029 fields = name.split('.')
2030 new = fields.pop()
2031 module, cls = self.clinic._module_and_class(fields)
2032 if cls:
2033 fail("Can't nest a module inside a class!")
2034 m = Module(name, module)
2035 module.modules[name] = m
2036 self.block.signatures.append(m)
2037
2038 def directive_class(self, name):
2039 fields = name.split('.')
2040 in_classes = False
2041 parent = self
2042 name = fields.pop()
2043 so_far = []
2044 module, cls = self.clinic._module_and_class(fields)
2045
Larry Hastings31826802013-10-19 00:09:25 -07002046 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002047 if cls:
2048 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002049 else:
2050 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002051 self.block.signatures.append(c)
2052
2053 def at_classmethod(self):
2054 assert self.kind is CALLABLE
2055 self.kind = CLASS_METHOD
2056
2057 def at_staticmethod(self):
2058 assert self.kind is CALLABLE
2059 self.kind = STATIC_METHOD
2060
2061 def at_coexist(self):
2062 assert self.coexist == False
2063 self.coexist = True
2064
Larry Hastingsebdcb502013-11-23 14:54:00 -08002065
Larry Hastings31826802013-10-19 00:09:25 -07002066 def parse(self, block):
2067 self.reset()
2068 self.block = block
2069 block_start = self.clinic.block_parser.line_number
2070 lines = block.input.split('\n')
2071 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2072 if '\t' in line:
2073 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2074 self.state(line)
2075
2076 self.next(self.state_terminal)
2077 self.state(None)
2078
2079 block.output = self.clinic.language.render(block.signatures)
2080
2081 @staticmethod
2082 def ignore_line(line):
2083 # ignore comment-only lines
2084 if line.lstrip().startswith('#'):
2085 return True
2086
2087 # Ignore empty lines too
2088 # (but not in docstring sections!)
2089 if not line.strip():
2090 return True
2091
2092 return False
2093
2094 @staticmethod
2095 def calculate_indent(line):
2096 return len(line) - len(line.strip())
2097
2098 def next(self, state, line=None):
2099 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2100 self.state = state
2101 if line is not None:
2102 self.state(line)
2103
2104 def state_dsl_start(self, line):
2105 # self.block = self.ClinicOutputBlock(self)
2106 if self.ignore_line(line):
2107 return
2108 self.next(self.state_modulename_name, line)
2109
2110 def state_modulename_name(self, line):
2111 # looking for declaration, which establishes the leftmost column
2112 # line should be
2113 # modulename.fnname [as c_basename] [-> return annotation]
2114 # square brackets denote optional syntax.
2115 #
2116 # (but we might find a directive first!)
2117 #
2118 # this line is permitted to start with whitespace.
2119 # we'll call this number of spaces F (for "function").
2120
2121 if not line.strip():
2122 return
2123
2124 self.indent.infer(line)
2125
2126 # is it a directive?
2127 fields = shlex.split(line)
2128 directive_name = fields[0]
2129 directive = self.directives.get(directive_name, None)
2130 if directive:
2131 directive(*fields[1:])
2132 return
2133
2134 line, _, returns = line.partition('->')
2135
2136 full_name, _, c_basename = line.partition(' as ')
2137 full_name = full_name.strip()
2138 c_basename = c_basename.strip() or None
2139
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002140 if not is_legal_py_identifier(full_name):
2141 fail("Illegal function name: {}".format(full_name))
2142 if c_basename and not is_legal_c_identifier(c_basename):
2143 fail("Illegal C basename: {}".format(c_basename))
2144
Larry Hastings31826802013-10-19 00:09:25 -07002145 if not returns:
2146 return_converter = CReturnConverter()
2147 else:
2148 ast_input = "def x() -> {}: pass".format(returns)
2149 module = None
2150 try:
2151 module = ast.parse(ast_input)
2152 except SyntaxError:
2153 pass
2154 if not module:
2155 fail("Badly-formed annotation for " + full_name + ": " + returns)
2156 try:
2157 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
2158 assert not legacy
2159 if name not in return_converters:
2160 fail("Error: No available return converter called " + repr(name))
2161 return_converter = return_converters[name](**kwargs)
2162 except ValueError:
2163 fail("Badly-formed annotation for " + full_name + ": " + returns)
2164
2165 fields = [x.strip() for x in full_name.split('.')]
2166 function_name = fields.pop()
2167 module, cls = self.clinic._module_and_class(fields)
2168
2169 if not module:
2170 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2171 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2172 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2173 self.block.signatures.append(self.function)
2174 self.next(self.state_parameters_start)
2175
2176 # Now entering the parameters section. The rules, formally stated:
2177 #
2178 # * All lines must be indented with spaces only.
2179 # * The first line must be a parameter declaration.
2180 # * The first line must be indented.
2181 # * This first line establishes the indent for parameters.
2182 # * We'll call this number of spaces P (for "parameter").
2183 # * Thenceforth:
2184 # * Lines indented with P spaces specify a parameter.
2185 # * Lines indented with > P spaces are docstrings for the previous
2186 # parameter.
2187 # * We'll call this number of spaces D (for "docstring").
2188 # * All subsequent lines indented with >= D spaces are stored as
2189 # part of the per-parameter docstring.
2190 # * All lines will have the first D spaces of the indent stripped
2191 # before they are stored.
2192 # * It's illegal to have a line starting with a number of spaces X
2193 # such that P < X < D.
2194 # * A line with < P spaces is the first line of the function
2195 # docstring, which ends processing for parameters and per-parameter
2196 # docstrings.
2197 # * The first line of the function docstring must be at the same
2198 # indent as the function declaration.
2199 # * It's illegal to have any line in the parameters section starting
2200 # with X spaces such that F < X < P. (As before, F is the indent
2201 # of the function declaration.)
2202 #
2203 ##############
2204 #
2205 # Also, currently Argument Clinic places the following restrictions on groups:
2206 # * Each group must contain at least one parameter.
2207 # * Each group may contain at most one group, which must be the furthest
2208 # thing in the group from the required parameters. (The nested group
2209 # must be the first in the group when it's before the required
2210 # parameters, and the last thing in the group when after the required
2211 # parameters.)
2212 # * There may be at most one (top-level) group to the left or right of
2213 # the required parameters.
2214 # * You must specify a slash, and it must be after all parameters.
2215 # (In other words: either all parameters are positional-only,
2216 # or none are.)
2217 #
2218 # Said another way:
2219 # * Each group must contain at least one parameter.
2220 # * All left square brackets before the required parameters must be
2221 # consecutive. (You can't have a left square bracket followed
2222 # by a parameter, then another left square bracket. You can't
2223 # have a left square bracket, a parameter, a right square bracket,
2224 # and then a left square bracket.)
2225 # * All right square brackets after the required parameters must be
2226 # consecutive.
2227 #
2228 # These rules are enforced with a single state variable:
2229 # "parameter_state". (Previously the code was a miasma of ifs and
2230 # separate boolean state variables.) The states are:
2231 #
2232 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2233 # 01 2 3 4 5 6 <- state transitions
2234 #
2235 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2236 # 1: ps_left_square_before. left square brackets before required parameters.
2237 # 2: ps_group_before. in a group, before required parameters.
2238 # 3: ps_required. required parameters. (renumber left groups!)
2239 # 4: ps_group_after. in a group, after required parameters.
2240 # 5: ps_right_square_after. right square brackets after required parameters.
2241 # 6: ps_seen_slash. seen slash.
2242 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2243 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2244
2245 def state_parameters_start(self, line):
2246 if self.ignore_line(line):
2247 return
2248
2249 # if this line is not indented, we have no parameters
2250 if not self.indent.infer(line):
2251 return self.next(self.state_function_docstring, line)
2252
2253 return self.next(self.state_parameter, line)
2254
2255
2256 def to_required(self):
2257 """
2258 Transition to the "required" parameter state.
2259 """
2260 if self.parameter_state != self.ps_required:
2261 self.parameter_state = self.ps_required
2262 for p in self.function.parameters.values():
2263 p.group = -p.group
2264
2265 def state_parameter(self, line):
2266 if self.ignore_line(line):
2267 return
2268
2269 assert self.indent.depth == 2
2270 indent = self.indent.infer(line)
2271 if indent == -1:
2272 # we outdented, must be to definition column
2273 return self.next(self.state_function_docstring, line)
2274
2275 if indent == 1:
2276 # we indented, must be to new parameter docstring column
2277 return self.next(self.state_parameter_docstring_start, line)
2278
2279 line = line.lstrip()
2280
2281 if line in ('*', '/', '[', ']'):
2282 self.parse_special_symbol(line)
2283 return
2284
2285 if self.parameter_state in (self.ps_start, self.ps_required):
2286 self.to_required()
2287 elif self.parameter_state == self.ps_left_square_before:
2288 self.parameter_state = self.ps_group_before
2289 elif self.parameter_state == self.ps_group_before:
2290 if not self.group:
2291 self.to_required()
2292 elif self.parameter_state == self.ps_group_after:
2293 pass
2294 else:
2295 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2296
2297 ast_input = "def x({}): pass".format(line)
2298 module = None
2299 try:
2300 module = ast.parse(ast_input)
2301 except SyntaxError:
2302 pass
2303 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07002304 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07002305
2306 function_args = module.body[0].args
2307 parameter = function_args.args[0]
2308
2309 if function_args.defaults:
2310 expr = function_args.defaults[0]
2311 # mild hack: explicitly support NULL as a default value
2312 if isinstance(expr, ast.Name) and expr.id == 'NULL':
2313 value = NULL
2314 else:
2315 value = ast.literal_eval(expr)
2316 else:
2317 value = unspecified
2318
2319 parameter_name = parameter.arg
2320 name, legacy, kwargs = self.parse_converter(parameter.annotation)
2321 dict = legacy_converters if legacy else converters
2322 legacy_str = "legacy " if legacy else ""
2323 if name not in dict:
2324 fail('{} is not a valid {}converter'.format(name, legacy_str))
2325 converter = dict[name](parameter_name, self.function, value, **kwargs)
2326
Larry Hastingsebdcb502013-11-23 14:54:00 -08002327 # special case: if it's the self converter,
2328 # don't actually add it to the parameter list
2329 if isinstance(converter, self_converter):
2330 if self.function.parameters or (self.parameter_state != self.ps_required):
2331 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
2332 if self.function.self_converter:
2333 fail("You can't specify the 'self' parameter more than once.")
2334 self.function.self_converter = converter
2335 self.parameter_state = self.ps_start
2336 return
2337
Larry Hastings31826802013-10-19 00:09:25 -07002338 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
2339 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
2340 self.function.parameters[parameter_name] = p
2341
2342 def parse_converter(self, annotation):
2343 if isinstance(annotation, ast.Str):
2344 return annotation.s, True, {}
2345
2346 if isinstance(annotation, ast.Name):
2347 return annotation.id, False, {}
2348
2349 assert isinstance(annotation, ast.Call)
2350
2351 name = annotation.func.id
2352 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
2353 return name, False, kwargs
2354
2355 def parse_special_symbol(self, symbol):
2356 if self.parameter_state == self.ps_seen_slash:
2357 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
2358
2359 if symbol == '*':
2360 if self.keyword_only:
2361 fail("Function " + self.function.name + " uses '*' more than once.")
2362 self.keyword_only = True
2363 elif symbol == '[':
2364 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
2365 self.parameter_state = self.ps_left_square_before
2366 elif self.parameter_state in (self.ps_required, self.ps_group_after):
2367 self.parameter_state = self.ps_group_after
2368 else:
2369 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2370 self.group += 1
2371 elif symbol == ']':
2372 if not self.group:
2373 fail("Function " + self.function.name + " has a ] without a matching [.")
2374 if not any(p.group == self.group for p in self.function.parameters.values()):
2375 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
2376 self.group -= 1
2377 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
2378 self.parameter_state = self.ps_group_before
2379 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
2380 self.parameter_state = self.ps_right_square_after
2381 else:
2382 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2383 elif symbol == '/':
2384 # ps_required is allowed here, that allows positional-only without option groups
2385 # to work (and have default values!)
2386 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
2387 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2388 if self.keyword_only:
2389 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2390 self.parameter_state = self.ps_seen_slash
2391 # fixup preceeding parameters
2392 for p in self.function.parameters.values():
2393 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
2394 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2395 p.kind = inspect.Parameter.POSITIONAL_ONLY
2396
2397 def state_parameter_docstring_start(self, line):
2398 self.parameter_docstring_indent = len(self.indent.margin)
2399 assert self.indent.depth == 3
2400 return self.next(self.state_parameter_docstring, line)
2401
2402 # every line of the docstring must start with at least F spaces,
2403 # where F > P.
2404 # these F spaces will be stripped.
2405 def state_parameter_docstring(self, line):
2406 stripped = line.strip()
2407 if stripped.startswith('#'):
2408 return
2409
2410 indent = self.indent.measure(line)
2411 if indent < self.parameter_docstring_indent:
2412 self.indent.infer(line)
2413 assert self.indent.depth < 3
2414 if self.indent.depth == 2:
2415 # back to a parameter
2416 return self.next(self.state_parameter, line)
2417 assert self.indent.depth == 1
2418 return self.next(self.state_function_docstring, line)
2419
2420 assert self.function.parameters
2421 last_parameter = next(reversed(list(self.function.parameters.values())))
2422
2423 new_docstring = last_parameter.docstring
2424
2425 if new_docstring:
2426 new_docstring += '\n'
2427 if stripped:
2428 new_docstring += self.indent.dedent(line)
2429
2430 last_parameter.docstring = new_docstring
2431
2432 # the final stanza of the DSL is the docstring.
2433 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07002434 if self.group:
2435 fail("Function " + self.function.name + " has a ] without a matching [.")
2436
2437 stripped = line.strip()
2438 if stripped.startswith('#'):
2439 return
2440
2441 new_docstring = self.function.docstring
2442 if new_docstring:
2443 new_docstring += "\n"
2444 if stripped:
2445 line = self.indent.dedent(line).rstrip()
2446 else:
2447 line = ''
2448 new_docstring += line
2449 self.function.docstring = new_docstring
2450
2451 def format_docstring(self):
2452 f = self.function
2453
2454 add, output = text_accumulator()
2455 parameters = list(f.parameters.values())
2456
2457 ##
2458 ## docstring first line
2459 ##
2460
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002461 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07002462 add('(')
2463
2464 # populate "right_bracket_count" field for every parameter
2465 if parameters:
2466 # for now, the only way Clinic supports positional-only parameters
2467 # is if all of them are positional-only.
2468 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
2469 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
2470 assert all(positional_only_parameters)
2471 for p in parameters:
2472 p.right_bracket_count = abs(p.group)
2473 else:
2474 # don't put any right brackets around non-positional-only parameters, ever.
2475 for p in parameters:
2476 p.right_bracket_count = 0
2477
2478 right_bracket_count = 0
2479
2480 def fix_right_bracket_count(desired):
2481 nonlocal right_bracket_count
2482 s = ''
2483 while right_bracket_count < desired:
2484 s += '['
2485 right_bracket_count += 1
2486 while right_bracket_count > desired:
2487 s += ']'
2488 right_bracket_count -= 1
2489 return s
2490
2491 added_star = False
2492 add_comma = False
2493
2494 for p in parameters:
2495 assert p.name
2496
2497 if p.is_keyword_only() and not added_star:
2498 added_star = True
2499 if add_comma:
2500 add(', ')
2501 add('*')
2502
2503 a = [p.name]
2504 if p.converter.is_optional():
2505 a.append('=')
2506 value = p.converter.default
2507 a.append(p.converter.doc_default)
2508 s = fix_right_bracket_count(p.right_bracket_count)
2509 s += "".join(a)
2510 if add_comma:
2511 add(', ')
2512 add(s)
2513 add_comma = True
2514
2515 add(fix_right_bracket_count(0))
2516 add(')')
2517
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002518 # if f.return_converter.doc_default:
2519 # add(' -> ')
2520 # add(f.return_converter.doc_default)
Larry Hastings31826802013-10-19 00:09:25 -07002521
2522 docstring_first_line = output()
2523
2524 # now fix up the places where the brackets look wrong
2525 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
2526
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002527 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07002528 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002529 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07002530 for p in parameters:
2531 if not p.docstring.strip():
2532 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002533 if spacer_line:
2534 add('\n')
2535 else:
2536 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07002537 add(" ")
2538 add(p.name)
2539 add('\n')
2540 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002541 parameters = output()
2542 if parameters:
2543 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07002544
2545 ##
2546 ## docstring body
2547 ##
2548
2549 docstring = f.docstring.rstrip()
2550 lines = [line.rstrip() for line in docstring.split('\n')]
2551
2552 # Enforce the summary line!
2553 # The first line of a docstring should be a summary of the function.
2554 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
2555 # by itself.
2556 #
2557 # Argument Clinic enforces the following rule:
2558 # * either the docstring is empty,
2559 # * or it must have a summary line.
2560 #
2561 # Guido said Clinic should enforce this:
2562 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
2563
2564 if len(lines) >= 2:
2565 if lines[1]:
2566 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
2567 "Every non-blank function docstring must start with\n" +
2568 "a single line summary followed by an empty line.")
2569 elif len(lines) == 1:
2570 # the docstring is only one line right now--the summary line.
2571 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002572 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07002573 lines.append('')
2574
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002575 parameters_marker_count = len(docstring.split('{parameters}')) - 1
2576 if parameters_marker_count > 1:
2577 fail('You may not specify {parameters} more than once in a docstring!')
2578
2579 if not parameters_marker_count:
2580 # insert after summary line
2581 lines.insert(2, '{parameters}')
2582
2583 # insert at front of docstring
2584 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07002585
2586 docstring = "\n".join(lines)
2587
2588 add(docstring)
2589 docstring = output()
2590
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002591 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07002592 docstring = docstring.rstrip()
2593
2594 return docstring
2595
2596 def state_terminal(self, line):
2597 """
2598 Called when processing the block is done.
2599 """
2600 assert not line
2601
2602 if not self.function:
2603 return
2604
Larry Hastings6d2ea212014-01-05 02:50:45 -08002605 if not self.function.self_converter:
2606 self.function.self_converter = self_converter("self", self.function)
2607
Larry Hastings31826802013-10-19 00:09:25 -07002608 if self.keyword_only:
2609 values = self.function.parameters.values()
2610 if not values:
2611 no_parameter_after_star = True
2612 else:
2613 last_parameter = next(reversed(list(values)))
2614 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
2615 if no_parameter_after_star:
2616 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
2617
2618 # remove trailing whitespace from all parameter docstrings
2619 for name, value in self.function.parameters.items():
2620 if not value:
2621 continue
2622 value.docstring = value.docstring.rstrip()
2623
2624 self.function.docstring = self.format_docstring()
2625
2626
2627# maps strings to callables.
2628# the callable should return an object
2629# that implements the clinic parser
2630# interface (__init__ and parse).
2631#
2632# example parsers:
2633# "clinic", handles the Clinic DSL
2634# "python", handles running Python code
2635#
2636parsers = {'clinic' : DSLParser, 'python': PythonParser}
2637
2638
2639clinic = None
2640
2641
2642def main(argv):
2643 import sys
2644
2645 if sys.version_info.major < 3 or sys.version_info.minor < 3:
2646 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
2647
2648 import argparse
2649 cmdline = argparse.ArgumentParser()
2650 cmdline.add_argument("-f", "--force", action='store_true')
2651 cmdline.add_argument("-o", "--output", type=str)
2652 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002653 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07002654 cmdline.add_argument("filename", type=str, nargs="*")
2655 ns = cmdline.parse_args(argv)
2656
2657 if ns.converters:
2658 if ns.filename:
2659 print("Usage error: can't specify --converters and a filename at the same time.")
2660 print()
2661 cmdline.print_usage()
2662 sys.exit(-1)
2663 converters = []
2664 return_converters = []
2665 ignored = set("""
2666 add_c_converter
2667 add_c_return_converter
2668 add_default_legacy_c_converter
2669 add_legacy_c_converter
2670 """.strip().split())
2671 module = globals()
2672 for name in module:
2673 for suffix, ids in (
2674 ("_return_converter", return_converters),
2675 ("_converter", converters),
2676 ):
2677 if name in ignored:
2678 continue
2679 if name.endswith(suffix):
2680 ids.append((name, name[:-len(suffix)]))
2681 break
2682 print()
2683
2684 print("Legacy converters:")
2685 legacy = sorted(legacy_converters)
2686 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
2687 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
2688 print()
2689
2690 for title, attribute, ids in (
2691 ("Converters", 'converter_init', converters),
2692 ("Return converters", 'return_converter_init', return_converters),
2693 ):
2694 print(title + ":")
2695 longest = -1
2696 for name, short_name in ids:
2697 longest = max(longest, len(short_name))
2698 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
2699 cls = module[name]
2700 callable = getattr(cls, attribute, None)
2701 if not callable:
2702 continue
2703 signature = inspect.signature(callable)
2704 parameters = []
2705 for parameter_name, parameter in signature.parameters.items():
2706 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2707 if parameter.default != inspect.Parameter.empty:
2708 s = '{}={!r}'.format(parameter_name, parameter.default)
2709 else:
2710 s = parameter_name
2711 parameters.append(s)
2712 print(' {}({})'.format(short_name, ', '.join(parameters)))
2713 # add_comma = False
2714 # for parameter_name, parameter in signature.parameters.items():
2715 # if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2716 # if add_comma:
2717 # parameters.append(', ')
2718 # else:
2719 # add_comma = True
2720 # s = parameter_name
2721 # if parameter.default != inspect.Parameter.empty:
2722 # s += '=' + repr(parameter.default)
2723 # parameters.append(s)
2724 # parameters.append(')')
2725
2726 # print(" ", short_name + "".join(parameters))
2727 print()
Larry Hastings78cf85c2014-01-04 12:44:57 -08002728 print("All converters also accept (doc_default=None, required=False, annotation=None).")
Larry Hastings31826802013-10-19 00:09:25 -07002729 print("All return converters also accept (doc_default=None).")
2730 sys.exit(0)
2731
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002732 if ns.make:
2733 if ns.output or ns.filename:
2734 print("Usage error: can't use -o or filenames with --make.")
2735 print()
2736 cmdline.print_usage()
2737 sys.exit(-1)
2738 for root, dirs, files in os.walk('.'):
2739 for rcs_dir in ('.svn', '.git', '.hg'):
2740 if rcs_dir in dirs:
2741 dirs.remove(rcs_dir)
2742 for filename in files:
2743 if not filename.endswith('.c'):
2744 continue
2745 path = os.path.join(root, filename)
2746 parse_file(path, verify=not ns.force)
2747 return
2748
Larry Hastings31826802013-10-19 00:09:25 -07002749 if not ns.filename:
2750 cmdline.print_usage()
2751 sys.exit(-1)
2752
2753 if ns.output and len(ns.filename) > 1:
2754 print("Usage error: can't use -o with multiple filenames.")
2755 print()
2756 cmdline.print_usage()
2757 sys.exit(-1)
2758
2759 for filename in ns.filename:
2760 parse_file(filename, output=ns.output, verify=not ns.force)
2761
2762
2763if __name__ == "__main__":
2764 sys.exit(main(sys.argv[1:]))