blob: cac90e1bdb90f38c6073b6712e4624ea2a4ea41a [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_pyobject_template(self, methoddef_flags=""):
404 return self.template_base("METH_NOARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700405static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800406{c_basename}({self_type}{self_name})
Larry Hastings31826802013-10-19 00:09:25 -0700407"""
408
Larry Hastingsebdcb502013-11-23 14:54:00 -0800409 def meth_noargs_template(self, methoddef_flags=""):
410 return self.template_base("METH_NOARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700411static {impl_return_type}
412{impl_prototype};
413
414static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800415{c_basename}({self_type}{self_name})
Larry Hastings31826802013-10-19 00:09:25 -0700416{{
417 PyObject *return_value = NULL;
418 {declarations}
419 {initializers}
420
421 {return_value} = {c_basename}_impl({impl_arguments});
422 {return_conversion}
423
424{exit_label}
425 {cleanup}
426 return return_value;
427}}
428
429static {impl_return_type}
430{impl_prototype}
431"""
432
Larry Hastingsebdcb502013-11-23 14:54:00 -0800433 def meth_o_template(self, methoddef_flags=""):
434 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700435static PyObject *
436{c_basename}({impl_parameters})
437"""
438
Larry Hastingsebdcb502013-11-23 14:54:00 -0800439 def meth_o_return_converter_template(self, methoddef_flags=""):
440 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700441static {impl_return_type}
442{impl_prototype};
443
444static PyObject *
445{c_basename}({impl_parameters})
446{{
447 PyObject *return_value = NULL;
448 {declarations}
449 {initializers}
450 _return_value = {c_basename}_impl({impl_arguments});
451 {return_conversion}
452
453{exit_label}
454 {cleanup}
455 return return_value;
456}}
457
458static {impl_return_type}
459{impl_prototype}
460"""
461
Larry Hastingsebdcb502013-11-23 14:54:00 -0800462 def option_group_template(self, methoddef_flags=""):
463 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700464static {impl_return_type}
465{impl_prototype};
466
467static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800468{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700469{{
470 PyObject *return_value = NULL;
471 {declarations}
472 {initializers}
473
474 {option_group_parsing}
475 {return_value} = {c_basename}_impl({impl_arguments});
476 {return_conversion}
477
478{exit_label}
479 {cleanup}
480 return return_value;
481}}
482
483static {impl_return_type}
484{impl_prototype}
485"""
486
Larry Hastingsebdcb502013-11-23 14:54:00 -0800487 def keywords_template(self, methoddef_flags=""):
488 return self.template_base("METH_VARARGS|METH_KEYWORDS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700489static {impl_return_type}
490{impl_prototype};
491
492static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800493{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
Larry Hastings31826802013-10-19 00:09:25 -0700494{{
495 PyObject *return_value = NULL;
496 static char *_keywords[] = {{{keywords}, NULL}};
497 {declarations}
498 {initializers}
499
500 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
501 "{format_units}:{name}", _keywords,
502 {parse_arguments}))
503 goto exit;
504 {return_value} = {c_basename}_impl({impl_arguments});
505 {return_conversion}
506
507{exit_label}
508 {cleanup}
509 return return_value;
510}}
511
512static {impl_return_type}
513{impl_prototype}
514"""
515
Larry Hastingsebdcb502013-11-23 14:54:00 -0800516 def positional_only_template(self, methoddef_flags=""):
517 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700518static {impl_return_type}
519{impl_prototype};
520
521static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800522{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700523{{
524 PyObject *return_value = NULL;
525 {declarations}
526 {initializers}
527
528 if (!PyArg_ParseTuple(args,
529 "{format_units}:{name}",
530 {parse_arguments}))
531 goto exit;
532 {return_value} = {c_basename}_impl({impl_arguments});
533 {return_conversion}
534
535{exit_label}
536 {cleanup}
537 return return_value;
538}}
539
540static {impl_return_type}
541{impl_prototype}
542"""
543
544 @staticmethod
545 def group_to_variable_name(group):
546 adjective = "left_" if group < 0 else "right_"
547 return "group_" + adjective + str(abs(group))
548
549 def render_option_group_parsing(self, f, template_dict):
550 # positional only, grouped, optional arguments!
551 # can be optional on the left or right.
552 # here's an example:
553 #
554 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
555 #
556 # Here group D are required, and all other groups are optional.
557 # (Group D's "group" is actually None.)
558 # We can figure out which sets of arguments we have based on
559 # how many arguments are in the tuple.
560 #
561 # Note that you need to count up on both sides. For example,
562 # you could have groups C+D, or C+D+E, or C+D+E+F.
563 #
564 # What if the number of arguments leads us to an ambiguous result?
565 # Clinic prefers groups on the left. So in the above example,
566 # five arguments would map to B+C, not C+D.
567
568 add, output = text_accumulator()
569 parameters = list(f.parameters.values())
570
571 groups = []
572 group = None
573 left = []
574 right = []
575 required = []
576 last = unspecified
577
578 for p in parameters:
579 group_id = p.group
580 if group_id != last:
581 last = group_id
582 group = []
583 if group_id < 0:
584 left.append(group)
585 elif group_id == 0:
586 group = required
587 else:
588 right.append(group)
589 group.append(p)
590
591 count_min = sys.maxsize
592 count_max = -1
593
594 add("switch (PyTuple_Size(args)) {{\n")
595 for subset in permute_optional_groups(left, required, right):
596 count = len(subset)
597 count_min = min(count_min, count)
598 count_max = max(count_max, count)
599
600 group_ids = {p.group for p in subset} # eliminate duplicates
601 d = {}
602 d['count'] = count
603 d['name'] = f.name
604 d['groups'] = sorted(group_ids)
605 d['format_units'] = "".join(p.converter.format_unit for p in subset)
606
607 parse_arguments = []
608 for p in subset:
609 p.converter.parse_argument(parse_arguments)
610 d['parse_arguments'] = ", ".join(parse_arguments)
611
612 group_ids.discard(0)
613 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
614 lines = "\n".join(lines)
615
616 s = """
617 case {count}:
618 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
619 return NULL;
620 {group_booleans}
621 break;
622"""[1:]
623 s = linear_format(s, group_booleans=lines)
624 s = s.format_map(d)
625 add(s)
626
627 add(" default:\n")
628 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
629 add(s.format(f.full_name, count_min, count_max))
630 add(' return NULL;\n')
631 add("}}")
632 template_dict['option_group_parsing'] = output()
633
634 def render_function(self, f):
635 if not f:
636 return ""
637
638 add, output = text_accumulator()
639 data = CRenderData()
640
Larry Hastings31826802013-10-19 00:09:25 -0700641 parameters = list(f.parameters.values())
642 converters = [p.converter for p in parameters]
643
644 template_dict = {}
645
646 full_name = f.full_name
647 template_dict['full_name'] = full_name
648
649 name = full_name.rpartition('.')[2]
650 template_dict['name'] = name
651
652 c_basename = f.c_basename or full_name.replace(".", "_")
653 template_dict['c_basename'] = c_basename
654
655 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
656 template_dict['methoddef_name'] = methoddef_name
657
658 template_dict['docstring'] = self.docstring_for_c_string(f)
659
Larry Hastings31826802013-10-19 00:09:25 -0700660 positional = has_option_groups = False
661
662 if parameters:
663 last_group = 0
664
665 for p in parameters:
666 c = p.converter
667
668 # insert group variable
669 group = p.group
670 if last_group != group:
671 last_group = group
672 if group:
673 group_name = self.group_to_variable_name(group)
674 data.impl_arguments.append(group_name)
675 data.declarations.append("int " + group_name + " = 0;")
676 data.impl_parameters.append("int " + group_name)
677 has_option_groups = True
678 c.render(p, data)
679
680 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
681 if has_option_groups:
682 assert positional
683
Larry Hastingsebdcb502013-11-23 14:54:00 -0800684 # now insert our "self" (or whatever) parameters
685 # (we deliberately don't call render on self converters)
686 stock_self = self_converter('self', f)
687 template_dict['self_name'] = stock_self.name
688 template_dict['self_type'] = stock_self.type
689 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
690 if f.self_converter.type != stock_self.type:
691 self_cast = '(' + f.self_converter.type + ')'
692 else:
693 self_cast = ''
694 data.impl_arguments.insert(0, self_cast + stock_self.name)
695
Larry Hastings31826802013-10-19 00:09:25 -0700696 f.return_converter.render(f, data)
697 template_dict['impl_return_type'] = f.return_converter.type
698
699 template_dict['declarations'] = "\n".join(data.declarations)
700 template_dict['initializers'] = "\n\n".join(data.initializers)
701 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
702 template_dict['format_units'] = ''.join(data.format_units)
703 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
704 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
705 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
706 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
707 template_dict['cleanup'] = "".join(data.cleanup)
708 template_dict['return_value'] = data.return_value
709
710 template_dict['impl_prototype'] = self.impl_prototype_template.format_map(template_dict)
711
712 default_return_converter = (not f.return_converter or
713 f.return_converter.type == 'PyObject *')
714
715 if not parameters:
716 if default_return_converter:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800717 template = self.meth_noargs_pyobject_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700718 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800719 template = self.meth_noargs_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700720 elif (len(parameters) == 1 and
721 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
722 not converters[0].is_optional() and
723 isinstance(converters[0], object_converter) and
724 converters[0].format_unit == 'O'):
725 if default_return_converter:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800726 template = self.meth_o_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700727 else:
728 # HACK
729 # we're using "impl_parameters" for the
730 # non-impl function, because that works
731 # better for METH_O. but that means we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800732 # must supress actually declaring the
Larry Hastings31826802013-10-19 00:09:25 -0700733 # impl's parameters as variables in the
734 # non-impl. but since it's METH_O, we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800735 # only have one anyway, so
736 # we don't have any problem finding it.
Larry Hastings31826802013-10-19 00:09:25 -0700737 declarations_copy = list(data.declarations)
738 before, pyobject, after = declarations_copy[0].partition('PyObject *')
739 assert not before, "hack failed, see comment"
740 assert pyobject, "hack failed, see comment"
741 assert after and after[0].isalpha(), "hack failed, see comment"
742 del declarations_copy[0]
743 template_dict['declarations'] = "\n".join(declarations_copy)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800744 template = self.meth_o_return_converter_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700745 elif has_option_groups:
746 self.render_option_group_parsing(f, template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800747 template = self.option_group_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700748 template = linear_format(template,
749 option_group_parsing=template_dict['option_group_parsing'])
750 elif positional:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800751 template = self.positional_only_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700752 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800753 template = self.keywords_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700754
755 template = linear_format(template,
756 declarations=template_dict['declarations'],
757 return_conversion=template_dict['return_conversion'],
758 initializers=template_dict['initializers'],
759 cleanup=template_dict['cleanup'],
760 )
761
762 # Only generate the "exit:" label
763 # if we have any gotos
764 need_exit_label = "goto exit;" in template
765 template = linear_format(template,
766 exit_label="exit:" if need_exit_label else ''
767 )
768
769 return template.format_map(template_dict)
770
771
772@contextlib.contextmanager
773def OverrideStdioWith(stdout):
774 saved_stdout = sys.stdout
775 sys.stdout = stdout
776 try:
777 yield
778 finally:
779 assert sys.stdout is stdout
780 sys.stdout = saved_stdout
781
782
783def create_regex(before, after):
784 """Create an re object for matching marker lines."""
785 pattern = r'^{}(\w+){}$'
786 return re.compile(pattern.format(re.escape(before), re.escape(after)))
787
788
789class Block:
790 r"""
791 Represents a single block of text embedded in
792 another file. If dsl_name is None, the block represents
793 verbatim text, raw original text from the file, in
794 which case "input" will be the only non-false member.
795 If dsl_name is not None, the block represents a Clinic
796 block.
797
798 input is always str, with embedded \n characters.
799 input represents the original text from the file;
800 if it's a Clinic block, it is the original text with
801 the body_prefix and redundant leading whitespace removed.
802
803 dsl_name is either str or None. If str, it's the text
804 found on the start line of the block between the square
805 brackets.
806
807 signatures is either list or None. If it's a list,
808 it may only contain clinic.Module, clinic.Class, and
809 clinic.Function objects. At the moment it should
810 contain at most one of each.
811
812 output is either str or None. If str, it's the output
813 from this block, with embedded '\n' characters.
814
815 indent is either str or None. It's the leading whitespace
816 that was found on every line of input. (If body_prefix is
817 not empty, this is the indent *after* removing the
818 body_prefix.)
819
820 preindent is either str or None. It's the whitespace that
821 was found in front of every line of input *before* the
822 "body_prefix" (see the Language object). If body_prefix
823 is empty, preindent must always be empty too.
824
825 To illustrate indent and preindent: Assume that '_'
826 represents whitespace. If the block processed was in a
827 Python file, and looked like this:
828 ____#/*[python]
829 ____#__for a in range(20):
830 ____#____print(a)
831 ____#[python]*/
832 "preindent" would be "____" and "indent" would be "__".
833
834 """
835 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
836 assert isinstance(input, str)
837 self.input = input
838 self.dsl_name = dsl_name
839 self.signatures = signatures or []
840 self.output = output
841 self.indent = indent
842 self.preindent = preindent
843
844
845class BlockParser:
846 """
847 Block-oriented parser for Argument Clinic.
848 Iterator, yields Block objects.
849 """
850
851 def __init__(self, input, language, *, verify=True):
852 """
853 "input" should be a str object
854 with embedded \n characters.
855
856 "language" should be a Language object.
857 """
858 language.validate()
859
860 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
861 self.block_start_line_number = self.line_number = 0
862
863 self.language = language
864 before, _, after = language.start_line.partition('{dsl_name}')
865 assert _ == '{dsl_name}'
866 self.start_re = create_regex(before, after)
867 self.verify = verify
868 self.last_checksum_re = None
869 self.last_dsl_name = None
870 self.dsl_name = None
871
872 def __iter__(self):
873 return self
874
875 def __next__(self):
876 if not self.input:
877 raise StopIteration
878
879 if self.dsl_name:
880 return_value = self.parse_clinic_block(self.dsl_name)
881 self.dsl_name = None
882 return return_value
883 return self.parse_verbatim_block()
884
885 def is_start_line(self, line):
886 match = self.start_re.match(line.lstrip())
887 return match.group(1) if match else None
888
889 def _line(self):
890 self.line_number += 1
891 return self.input.pop()
892
893 def parse_verbatim_block(self):
894 add, output = text_accumulator()
895 self.block_start_line_number = self.line_number
896
897 while self.input:
898 line = self._line()
899 dsl_name = self.is_start_line(line)
900 if dsl_name:
901 self.dsl_name = dsl_name
902 break
903 add(line)
904
905 return Block(output())
906
907 def parse_clinic_block(self, dsl_name):
908 input_add, input_output = text_accumulator()
909 self.block_start_line_number = self.line_number + 1
910 stop_line = self.language.stop_line.format(dsl_name=dsl_name) + '\n'
911 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
912
913 # consume body of program
914 while self.input:
915 line = self._line()
916 if line == stop_line or self.is_start_line(line):
917 break
918 if body_prefix:
919 line = line.lstrip()
920 assert line.startswith(body_prefix)
921 line = line[len(body_prefix):]
922 input_add(line)
923
924 # consume output and checksum line, if present.
925 if self.last_dsl_name == dsl_name:
926 checksum_re = self.last_checksum_re
927 else:
928 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
929 assert _ == '{checksum}'
930 checksum_re = create_regex(before, after)
931 self.last_dsl_name = dsl_name
932 self.last_checksum_re = checksum_re
933
934 # scan forward for checksum line
935 output_add, output_output = text_accumulator()
936 checksum = None
937 while self.input:
938 line = self._line()
939 match = checksum_re.match(line.lstrip())
940 checksum = match.group(1) if match else None
941 if checksum:
942 break
943 output_add(line)
944 if self.is_start_line(line):
945 break
946
Larry Hastingsef3b1fb2013-10-22 23:26:23 -0700947 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -0700948 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -0700949 if self.verify:
950 computed = compute_checksum(output)
951 if checksum != computed:
952 fail("Checksum mismatch!\nExpected: {}\nComputed: {}".format(checksum, computed))
953 else:
954 # put back output
955 self.input.extend(reversed(output.splitlines(keepends=True)))
956 self.line_number -= len(output)
957 output = None
958
959 return Block(input_output(), dsl_name, output=output)
960
961
962class BlockPrinter:
963
964 def __init__(self, language, f=None):
965 self.language = language
966 self.f = f or io.StringIO()
967
968 def print_block(self, block):
969 input = block.input
970 output = block.output
971 dsl_name = block.dsl_name
972 write = self.f.write
973
Larry Hastings31826802013-10-19 00:09:25 -0700974 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
975
976 if not dsl_name:
977 write(input)
978 return
979
980 write(self.language.start_line.format(dsl_name=dsl_name))
981 write("\n")
982
983 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
984 if not body_prefix:
985 write(input)
986 else:
987 for line in input.split('\n'):
988 write(body_prefix)
989 write(line)
990 write("\n")
991
992 write(self.language.stop_line.format(dsl_name=dsl_name))
993 write("\n")
994
995 output = block.output
996 if output:
997 write(output)
998 if not output.endswith('\n'):
999 write('\n')
1000
1001 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
1002 write("\n")
1003
1004
1005# maps strings to Language objects.
1006# "languages" maps the name of the language ("C", "Python").
1007# "extensions" maps the file extension ("c", "py").
1008languages = { 'C': CLanguage, 'Python': PythonLanguage }
1009extensions = { 'c': CLanguage, 'h': CLanguage, 'py': PythonLanguage }
1010
1011
1012# maps strings to callables.
1013# these callables must be of the form:
1014# def foo(name, default, *, ...)
1015# The callable may have any number of keyword-only parameters.
1016# The callable must return a CConverter object.
1017# The callable should not call builtins.print.
1018converters = {}
1019
1020# maps strings to callables.
1021# these callables follow the same rules as those for "converters" above.
1022# note however that they will never be called with keyword-only parameters.
1023legacy_converters = {}
1024
1025
1026# maps strings to callables.
1027# these callables must be of the form:
1028# def foo(*, ...)
1029# The callable may have any number of keyword-only parameters.
1030# The callable must return a CConverter object.
1031# The callable should not call builtins.print.
1032return_converters = {}
1033
1034class Clinic:
1035 def __init__(self, language, printer=None, *, verify=True, filename=None):
1036 # maps strings to Parser objects.
1037 # (instantiated from the "parsers" global.)
1038 self.parsers = {}
1039 self.language = language
1040 self.printer = printer or BlockPrinter(language)
1041 self.verify = verify
1042 self.filename = filename
1043 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001044 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -07001045
1046 global clinic
1047 clinic = self
1048
1049 def parse(self, input):
1050 printer = self.printer
1051 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1052 for block in self.block_parser:
1053 dsl_name = block.dsl_name
1054 if dsl_name:
1055 if dsl_name not in self.parsers:
1056 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1057 self.parsers[dsl_name] = parsers[dsl_name](self)
1058 parser = self.parsers[dsl_name]
1059 parser.parse(block)
1060 printer.print_block(block)
1061 return printer.f.getvalue()
1062
1063 def _module_and_class(self, fields):
1064 """
1065 fields should be an iterable of field names.
1066 returns a tuple of (module, class).
1067 the module object could actually be self (a clinic object).
1068 this function is only ever used to find the parent of where
1069 a new class/module should go.
1070 """
1071 in_classes = False
1072 parent = module = self
1073 cls = None
1074 so_far = []
1075
1076 for field in fields:
1077 so_far.append(field)
1078 if not in_classes:
1079 child = parent.modules.get(field)
1080 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001081 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001082 continue
1083 in_classes = True
1084 if not hasattr(parent, 'classes'):
1085 return module, cls
1086 child = parent.classes.get(field)
1087 if not child:
1088 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1089 cls = parent = child
1090
1091 return module, cls
1092
1093
1094def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1095 extension = os.path.splitext(filename)[1][1:]
1096 if not extension:
1097 fail("Can't extract file type for file " + repr(filename))
1098
1099 try:
1100 language = extensions[extension]()
1101 except KeyError:
1102 fail("Can't identify file type for file " + repr(filename))
1103
1104 clinic = Clinic(language, verify=verify, filename=filename)
1105
1106 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001107 raw = f.read()
1108
1109 cooked = clinic.parse(raw)
1110 if cooked == raw:
1111 return
Larry Hastings31826802013-10-19 00:09:25 -07001112
1113 directory = os.path.dirname(filename) or '.'
1114
1115 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001116 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001117 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1118 with open(tmpfilename, "wb") as f:
1119 f.write(bytes)
1120 os.replace(tmpfilename, output or filename)
1121
1122
1123def compute_checksum(input):
1124 input = input or ''
1125 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1126
1127
1128
1129
1130class PythonParser:
1131 def __init__(self, clinic):
1132 pass
1133
1134 def parse(self, block):
1135 s = io.StringIO()
1136 with OverrideStdioWith(s):
1137 exec(block.input)
1138 block.output = s.getvalue()
1139
1140
1141class Module:
1142 def __init__(self, name, module=None):
1143 self.name = name
1144 self.module = self.parent = module
1145
1146 self.modules = collections.OrderedDict()
1147 self.classes = collections.OrderedDict()
1148 self.functions = []
1149
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001150 def __repr__(self):
1151 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1152
Larry Hastings31826802013-10-19 00:09:25 -07001153class Class:
1154 def __init__(self, name, module=None, cls=None):
1155 self.name = name
1156 self.module = module
1157 self.cls = cls
1158 self.parent = cls or module
1159
1160 self.classes = collections.OrderedDict()
1161 self.functions = []
1162
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001163 def __repr__(self):
1164 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1165
1166
Larry Hastings31826802013-10-19 00:09:25 -07001167DATA, CALLABLE, METHOD, STATIC_METHOD, CLASS_METHOD = range(5)
1168
1169class Function:
1170 """
1171 Mutable duck type for inspect.Function.
1172
1173 docstring - a str containing
1174 * embedded line breaks
1175 * text outdented to the left margin
1176 * no trailing whitespace.
1177 It will always be true that
1178 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1179 """
1180
1181 def __init__(self, parameters=None, *, name,
1182 module, cls=None, c_basename=None,
1183 full_name=None,
1184 return_converter, return_annotation=_empty,
1185 docstring=None, kind=CALLABLE, coexist=False):
1186 self.parameters = parameters or collections.OrderedDict()
1187 self.return_annotation = return_annotation
1188 self.name = name
1189 self.full_name = full_name
1190 self.module = module
1191 self.cls = cls
1192 self.parent = cls or module
1193 self.c_basename = c_basename
1194 self.return_converter = return_converter
1195 self.docstring = docstring or ''
1196 self.kind = kind
1197 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001198 self.self_converter = None
1199
1200 @property
1201 def methoddef_flags(self):
1202 flags = []
1203 if self.kind == CLASS_METHOD:
1204 flags.append('METH_CLASS')
1205 elif self.kind == STATIC_METHOD:
1206 flags.append('METH_STATIC')
1207 else:
1208 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1209 if self.coexist:
1210 flags.append('METH_COEXIST')
1211 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001212
1213 def __repr__(self):
1214 return '<clinic.Function ' + self.name + '>'
1215
1216
1217class Parameter:
1218 """
1219 Mutable duck type of inspect.Parameter.
1220 """
1221
1222 def __init__(self, name, kind, *, default=_empty,
1223 function, converter, annotation=_empty,
1224 docstring=None, group=0):
1225 self.name = name
1226 self.kind = kind
1227 self.default = default
1228 self.function = function
1229 self.converter = converter
1230 self.annotation = annotation
1231 self.docstring = docstring or ''
1232 self.group = group
1233
1234 def __repr__(self):
1235 return '<clinic.Parameter ' + self.name + '>'
1236
1237 def is_keyword_only(self):
1238 return self.kind == inspect.Parameter.KEYWORD_ONLY
1239
1240py_special_values = {
1241 NULL: "None",
1242}
1243
1244def py_repr(o):
1245 special = py_special_values.get(o)
1246 if special:
1247 return special
1248 return repr(o)
1249
1250
1251c_special_values = {
1252 NULL: "NULL",
1253 None: "Py_None",
1254}
1255
1256def c_repr(o):
1257 special = c_special_values.get(o)
1258 if special:
1259 return special
1260 if isinstance(o, str):
1261 return '"' + quoted_for_c_string(o) + '"'
1262 return repr(o)
1263
1264def add_c_converter(f, name=None):
1265 if not name:
1266 name = f.__name__
1267 if not name.endswith('_converter'):
1268 return f
1269 name = name[:-len('_converter')]
1270 converters[name] = f
1271 return f
1272
1273def add_default_legacy_c_converter(cls):
1274 # automatically add converter for default format unit
1275 # (but without stomping on the existing one if it's already
1276 # set, in case you subclass)
1277 if ((cls.format_unit != 'O&') and
1278 (cls.format_unit not in legacy_converters)):
1279 legacy_converters[cls.format_unit] = cls
1280 return cls
1281
1282def add_legacy_c_converter(format_unit, **kwargs):
1283 """
1284 Adds a legacy converter.
1285 """
1286 def closure(f):
1287 if not kwargs:
1288 added_f = f
1289 else:
1290 added_f = functools.partial(f, **kwargs)
1291 legacy_converters[format_unit] = added_f
1292 return f
1293 return closure
1294
1295class CConverterAutoRegister(type):
1296 def __init__(cls, name, bases, classdict):
1297 add_c_converter(cls)
1298 add_default_legacy_c_converter(cls)
1299
1300class CConverter(metaclass=CConverterAutoRegister):
1301 """
1302 For the init function, self, name, function, and default
1303 must be keyword-or-positional parameters. All other
1304 parameters (including "required" and "doc_default")
1305 must be keyword-only.
1306 """
1307
1308 type = None
1309 format_unit = 'O&'
1310
1311 # The Python default value for this parameter, as a Python value.
1312 # Or "unspecified" if there is no default.
1313 default = unspecified
1314
Larry Hastings31826802013-10-19 00:09:25 -07001315 # "default" as it should appear in the documentation, as a string.
1316 # Or None if there is no default.
1317 doc_default = None
1318
Larry Hastingsabc716b2013-11-20 09:13:52 -08001319 # "default" converted into a str for rendering into Python code.
1320 py_default = None
1321
Larry Hastings31826802013-10-19 00:09:25 -07001322 # "default" converted into a C value, as a string.
1323 # Or None if there is no default.
1324 c_default = None
1325
Larry Hastingsabc716b2013-11-20 09:13:52 -08001326 # The default value used to initialize the C variable when
1327 # there is no default, but not specifying a default may
1328 # result in an "uninitialized variable" warning. This can
1329 # easily happen when using option groups--although
1330 # properly-written code won't actually use the variable,
1331 # the variable does get passed in to the _impl. (Ah, if
1332 # only dataflow analysis could inline the static function!)
1333 #
1334 # This value is specified as a string.
1335 # Every non-abstract subclass should supply a valid value.
1336 c_ignored_default = 'NULL'
1337
Larry Hastings31826802013-10-19 00:09:25 -07001338 # The C converter *function* to be used, if any.
1339 # (If this is not None, format_unit must be 'O&'.)
1340 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001341
Larry Hastings31826802013-10-19 00:09:25 -07001342 encoding = None
1343 impl_by_reference = False
1344 parse_by_reference = True
1345 length = False
1346
1347 def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs):
1348 self.function = function
1349 self.name = name
1350
1351 if default is not unspecified:
1352 self.default = default
1353 self.py_default = py_repr(default)
1354 self.doc_default = doc_default if doc_default is not None else self.py_default
1355 self.c_default = c_repr(default)
1356 elif doc_default is not None:
1357 fail(function.fullname + " argument " + name + " specified a 'doc_default' without having a 'default'")
1358 if annotation != unspecified:
1359 fail("The 'annotation' parameter is not currently permitted.")
1360 self.required = required
1361 self.converter_init(**kwargs)
1362
1363 def converter_init(self):
1364 pass
1365
1366 def is_optional(self):
1367 return (self.default is not unspecified) and (not self.required)
1368
1369 def render(self, parameter, data):
1370 """
1371 parameter is a clinic.Parameter instance.
1372 data is a CRenderData instance.
1373 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001374 self.parameter = parameter
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001375 name = ensure_legal_c_identifier(self.name)
Larry Hastings31826802013-10-19 00:09:25 -07001376
1377 # declarations
1378 d = self.declaration()
1379 data.declarations.append(d)
1380
1381 # initializers
1382 initializers = self.initialize()
1383 if initializers:
1384 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1385
1386 # impl_arguments
1387 s = ("&" if self.impl_by_reference else "") + name
1388 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001389 if self.length:
1390 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001391
1392 # keywords
1393 data.keywords.append(name)
1394
1395 # format_units
1396 if self.is_optional() and '|' not in data.format_units:
1397 data.format_units.append('|')
1398 if parameter.is_keyword_only() and '$' not in data.format_units:
1399 data.format_units.append('$')
1400 data.format_units.append(self.format_unit)
1401
1402 # parse_arguments
1403 self.parse_argument(data.parse_arguments)
1404
1405 # impl_parameters
1406 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001407 if self.length:
1408 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001409
1410 # cleanup
1411 cleanup = self.cleanup()
1412 if cleanup:
1413 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1414
Larry Hastingsebdcb502013-11-23 14:54:00 -08001415 def length_name(self):
1416 """Computes the name of the associated "length" variable."""
1417 if not self.length:
1418 return None
1419 return ensure_legal_c_identifier(self.name) + "_length"
1420
Larry Hastings31826802013-10-19 00:09:25 -07001421 # Why is this one broken out separately?
1422 # For "positional-only" function parsing,
1423 # which generates a bunch of PyArg_ParseTuple calls.
1424 def parse_argument(self, list):
1425 assert not (self.converter and self.encoding)
1426 if self.format_unit == 'O&':
1427 assert self.converter
1428 list.append(self.converter)
1429
1430 if self.encoding:
1431 list.append(self.encoding)
1432
Larry Hastingsebdcb502013-11-23 14:54:00 -08001433 legal_name = ensure_legal_c_identifier(self.name)
1434 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001435 list.append(s)
1436
Larry Hastingsebdcb502013-11-23 14:54:00 -08001437 if self.length:
1438 list.append("&" + self.length_name())
1439
Larry Hastings31826802013-10-19 00:09:25 -07001440 #
1441 # All the functions after here are intended as extension points.
1442 #
1443
1444 def simple_declaration(self, by_reference=False):
1445 """
1446 Computes the basic declaration of the variable.
1447 Used in computing the prototype declaration and the
1448 variable declaration.
1449 """
1450 prototype = [self.type]
1451 if by_reference or not self.type.endswith('*'):
1452 prototype.append(" ")
1453 if by_reference:
1454 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001455 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001456 return "".join(prototype)
1457
1458 def declaration(self):
1459 """
1460 The C statement to declare this variable.
1461 """
1462 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08001463 default = self.c_default
1464 if not default and self.parameter.group:
1465 default = self.c_ignored_default
1466 if default:
Larry Hastings31826802013-10-19 00:09:25 -07001467 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08001468 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07001469 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001470 if self.length:
1471 declaration.append('\nPy_ssize_clean_t ')
1472 declaration.append(self.length_name())
1473 declaration.append(';')
Larry Hastings31826802013-10-19 00:09:25 -07001474 return "".join(declaration)
1475
1476 def initialize(self):
1477 """
1478 The C statements required to set up this variable before parsing.
1479 Returns a string containing this code indented at column 0.
1480 If no initialization is necessary, returns an empty string.
1481 """
1482 return ""
1483
1484 def cleanup(self):
1485 """
1486 The C statements required to clean up after this variable.
1487 Returns a string containing this code indented at column 0.
1488 If no cleanup is necessary, returns an empty string.
1489 """
1490 return ""
1491
1492
1493class bool_converter(CConverter):
1494 type = 'int'
1495 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001496 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07001497
1498 def converter_init(self):
1499 self.default = bool(self.default)
1500 self.c_default = str(int(self.default))
1501
1502class char_converter(CConverter):
1503 type = 'char'
1504 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001505 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001506
1507@add_legacy_c_converter('B', bitwise=True)
1508class byte_converter(CConverter):
1509 type = 'byte'
1510 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001511 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001512
1513 def converter_init(self, *, bitwise=False):
1514 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001515 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07001516
1517class short_converter(CConverter):
1518 type = 'short'
1519 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001520 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001521
1522class unsigned_short_converter(CConverter):
1523 type = 'unsigned short'
1524 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001525 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001526
1527 def converter_init(self, *, bitwise=False):
1528 if not bitwise:
1529 fail("Unsigned shorts must be bitwise (for now).")
1530
Larry Hastingsebdcb502013-11-23 14:54:00 -08001531@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07001532class int_converter(CConverter):
1533 type = 'int'
1534 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001535 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001536
Larry Hastingsebdcb502013-11-23 14:54:00 -08001537 def converter_init(self, *, types='int'):
1538 if types == 'str':
1539 self.format_unit = 'C'
1540 elif types != 'int':
1541 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07001542
1543class unsigned_int_converter(CConverter):
1544 type = 'unsigned int'
1545 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001546 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001547
1548 def converter_init(self, *, bitwise=False):
1549 if not bitwise:
1550 fail("Unsigned ints must be bitwise (for now).")
1551
1552class long_converter(CConverter):
1553 type = 'long'
1554 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001555 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001556
1557class unsigned_long_converter(CConverter):
1558 type = 'unsigned long'
1559 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001560 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001561
1562 def converter_init(self, *, bitwise=False):
1563 if not bitwise:
1564 fail("Unsigned longs must be bitwise (for now).")
1565
1566class PY_LONG_LONG_converter(CConverter):
1567 type = 'PY_LONG_LONG'
1568 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001569 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001570
1571class unsigned_PY_LONG_LONG_converter(CConverter):
1572 type = 'unsigned PY_LONG_LONG'
1573 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001574 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001575
1576 def converter_init(self, *, bitwise=False):
1577 if not bitwise:
1578 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
1579
1580class Py_ssize_t_converter(CConverter):
1581 type = 'Py_ssize_t'
1582 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001583 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001584
1585
1586class float_converter(CConverter):
1587 type = 'float'
1588 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001589 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001590
1591class double_converter(CConverter):
1592 type = 'double'
1593 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001594 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001595
1596
1597class Py_complex_converter(CConverter):
1598 type = 'Py_complex'
1599 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001600 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07001601
1602
1603class object_converter(CConverter):
1604 type = 'PyObject *'
1605 format_unit = 'O'
1606
1607 def converter_init(self, *, type=None):
1608 if type:
1609 assert isinstance(type, str)
1610 assert type.isidentifier()
1611 try:
1612 type = eval(type)
1613 # need more of these!
1614 type = {
1615 str: '&PyUnicode_Type',
1616 }[type]
1617 except NameError:
1618 type = type
1619 self.format_unit = 'O!'
1620 self.encoding = type
1621
1622
Larry Hastingsebdcb502013-11-23 14:54:00 -08001623@add_legacy_c_converter('s#', length=True)
1624@add_legacy_c_converter('y', type="bytes")
1625@add_legacy_c_converter('y#', type="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001626@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001627@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001628class str_converter(CConverter):
1629 type = 'const char *'
1630 format_unit = 's'
1631
Larry Hastingsebdcb502013-11-23 14:54:00 -08001632 def converter_init(self, *, encoding=None, types="str",
1633 length=False, nullable=False, zeroes=False):
1634
1635 types = set(types.strip().split())
1636 bytes_type = set(("bytes",))
1637 str_type = set(("str",))
1638 all_3_type = set(("bytearray",)) | bytes_type | str_type
1639 is_bytes = types == bytes_type
1640 is_str = types == str_type
1641 is_all_3 = types == all_3_type
1642
1643 self.length = bool(length)
1644 format_unit = None
1645
1646 if encoding:
1647 self.encoding = encoding
1648
1649 if is_str and not (length or zeroes or nullable):
1650 format_unit = 'es'
1651 elif is_all_3 and not (length or zeroes or nullable):
1652 format_unit = 'et'
1653 elif is_str and length and zeroes and not nullable:
1654 format_unit = 'es#'
1655 elif is_all_3 and length and not (nullable or zeroes):
1656 format_unit = 'et#'
1657
1658 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08001659 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001660 # TODO set pointer to NULL
1661 # TODO add cleanup for buffer
1662 pass
1663
1664 else:
1665 if zeroes:
1666 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
1667
1668 if is_bytes and not (nullable or length):
1669 format_unit = 'y'
1670 elif is_bytes and length and not nullable:
1671 format_unit = 'y#'
1672 elif is_str and not (nullable or length):
1673 format_unit = 's'
1674 elif is_str and length and not nullable:
1675 format_unit = 's#'
1676 elif is_str and nullable and not length:
1677 format_unit = 'z'
1678 elif is_str and nullable and length:
1679 format_unit = 'z#'
1680
1681 if not format_unit:
1682 fail("str_converter: illegal combination of arguments")
1683 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001684
1685
1686class PyBytesObject_converter(CConverter):
1687 type = 'PyBytesObject *'
1688 format_unit = 'S'
1689
1690class PyByteArrayObject_converter(CConverter):
1691 type = 'PyByteArrayObject *'
1692 format_unit = 'Y'
1693
1694class unicode_converter(CConverter):
1695 type = 'PyObject *'
1696 format_unit = 'U'
1697
Larry Hastingsebdcb502013-11-23 14:54:00 -08001698@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001699@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001700@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001701class Py_UNICODE_converter(CConverter):
1702 type = 'Py_UNICODE *'
1703 format_unit = 'u'
1704
Larry Hastingsebdcb502013-11-23 14:54:00 -08001705 def converter_init(self, *, nullable=False, length=False):
1706 format_unit = 'Z' if nullable else 'u'
1707 if length:
1708 format_unit += '#'
1709 self.length = True
1710 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001711
Larry Hastingsebdcb502013-11-23 14:54:00 -08001712#
1713# We define three string conventions for buffer types in the 'types' argument:
1714# 'buffer' : any object supporting the buffer interface
1715# 'rwbuffer': any object supporting the buffer interface, but must be writeable
1716# 'robuffer': any object supporting the buffer interface, but must not be writeable
1717#
1718@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
1719@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
1720@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07001721class Py_buffer_converter(CConverter):
1722 type = 'Py_buffer'
1723 format_unit = 'y*'
1724 impl_by_reference = True
Larry Hastingsabc716b2013-11-20 09:13:52 -08001725 c_ignored_default = "{NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07001726
Larry Hastingsebdcb502013-11-23 14:54:00 -08001727 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
1728 types = set(types.strip().split())
1729 bytes_type = set(('bytes',))
1730 bytearray_type = set(('bytearray',))
1731 buffer_type = set(('buffer',))
1732 rwbuffer_type = set(('rwbuffer',))
1733 robuffer_type = set(('robuffer',))
1734 str_type = set(('str',))
1735 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
1736
1737 format_unit = None
1738 if types == (str_type | bytes_bytearray_buffer_type):
1739 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07001740 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001741 if nullable:
1742 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
1743 elif types == (bytes_bytearray_buffer_type):
1744 format_unit = 'y*'
1745 elif types == (bytearray_type | rwuffer_type):
1746 format_unit = 'w*'
1747 if not format_unit:
1748 fail("Py_buffer_converter: illegal combination of arguments")
1749
1750 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001751
1752 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001753 name = ensure_legal_c_identifier(self.name)
1754 return "".join(["if (", name, ".buf)\n PyBuffer_Release(&", name, ");\n"])
1755
1756
1757class self_converter(CConverter):
1758 """
1759 A special-case converter:
1760 this is the default converter used for "self".
1761 """
1762 type = "PyObject *"
1763 def converter_init(self):
1764 f = self.function
1765 if f.kind == CALLABLE:
1766 if f.cls:
1767 self.name = "self"
1768 else:
1769 self.name = "module"
1770 self.type = "PyModuleDef *"
1771 elif f.kind == STATIC_METHOD:
1772 self.name = "null"
1773 self.type = "void *"
1774 elif f.kind == CLASS_METHOD:
1775 self.name = "cls"
1776 self.type = "PyTypeObject *"
1777
1778 def render(self, parameter, data):
1779 fail("render() should never be called on self_converter instances")
1780
Larry Hastings31826802013-10-19 00:09:25 -07001781
1782
1783def add_c_return_converter(f, name=None):
1784 if not name:
1785 name = f.__name__
1786 if not name.endswith('_return_converter'):
1787 return f
1788 name = name[:-len('_return_converter')]
1789 return_converters[name] = f
1790 return f
1791
1792
1793class CReturnConverterAutoRegister(type):
1794 def __init__(cls, name, bases, classdict):
1795 add_c_return_converter(cls)
1796
1797class CReturnConverter(metaclass=CReturnConverterAutoRegister):
1798
1799 type = 'PyObject *'
1800 default = None
1801
1802 def __init__(self, *, doc_default=None, **kwargs):
1803 self.doc_default = doc_default
1804 try:
1805 self.return_converter_init(**kwargs)
1806 except TypeError as e:
1807 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
1808 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
1809
1810 def return_converter_init(self):
1811 pass
1812
1813 def declare(self, data, name="_return_value"):
1814 line = []
1815 add = line.append
1816 add(self.type)
1817 if not self.type.endswith('*'):
1818 add(' ')
1819 add(name + ';')
1820 data.declarations.append(''.join(line))
1821 data.return_value = name
1822
1823 def err_occurred_if(self, expr, data):
1824 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
1825
1826 def err_occurred_if_null_pointer(self, variable, data):
1827 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
1828
1829 def render(self, function, data):
1830 """
1831 function is a clinic.Function instance.
1832 data is a CRenderData instance.
1833 """
1834 pass
1835
1836add_c_return_converter(CReturnConverter, 'object')
1837
1838class int_return_converter(CReturnConverter):
1839 type = 'int'
1840
1841 def render(self, function, data):
1842 self.declare(data)
1843 self.err_occurred_if("_return_value == -1", data)
1844 data.return_conversion.append(
1845 'return_value = PyLong_FromLong((long)_return_value);\n')
1846
1847
1848class long_return_converter(CReturnConverter):
1849 type = 'long'
1850
1851 def render(self, function, data):
1852 self.declare(data)
1853 self.err_occurred_if("_return_value == -1", data)
1854 data.return_conversion.append(
1855 'return_value = PyLong_FromLong(_return_value);\n')
1856
1857
1858class Py_ssize_t_return_converter(CReturnConverter):
1859 type = 'Py_ssize_t'
1860
1861 def render(self, function, data):
1862 self.declare(data)
1863 self.err_occurred_if("_return_value == -1", data)
1864 data.return_conversion.append(
1865 'return_value = PyLong_FromSsize_t(_return_value);\n')
1866
1867
1868class DecodeFSDefault_return_converter(CReturnConverter):
1869 type = 'char *'
1870
1871 def render(self, function, data):
1872 self.declare(data)
1873 self.err_occurred_if_null_pointer("_return_value", data)
1874 data.return_conversion.append(
1875 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
1876
1877
1878class IndentStack:
1879 def __init__(self):
1880 self.indents = []
1881 self.margin = None
1882
1883 def _ensure(self):
1884 if not self.indents:
1885 fail('IndentStack expected indents, but none are defined.')
1886
1887 def measure(self, line):
1888 """
1889 Returns the length of the line's margin.
1890 """
1891 if '\t' in line:
1892 fail('Tab characters are illegal in the Clinic DSL.')
1893 stripped = line.lstrip()
1894 if not len(stripped):
1895 # we can't tell anything from an empty line
1896 # so just pretend it's indented like our current indent
1897 self._ensure()
1898 return self.indents[-1]
1899 return len(line) - len(stripped)
1900
1901 def infer(self, line):
1902 """
1903 Infer what is now the current margin based on this line.
1904 Returns:
1905 1 if we have indented (or this is the first margin)
1906 0 if the margin has not changed
1907 -N if we have dedented N times
1908 """
1909 indent = self.measure(line)
1910 margin = ' ' * indent
1911 if not self.indents:
1912 self.indents.append(indent)
1913 self.margin = margin
1914 return 1
1915 current = self.indents[-1]
1916 if indent == current:
1917 return 0
1918 if indent > current:
1919 self.indents.append(indent)
1920 self.margin = margin
1921 return 1
1922 # indent < current
1923 if indent not in self.indents:
1924 fail("Illegal outdent.")
1925 outdent_count = 0
1926 while indent != current:
1927 self.indents.pop()
1928 current = self.indents[-1]
1929 outdent_count -= 1
1930 self.margin = margin
1931 return outdent_count
1932
1933 @property
1934 def depth(self):
1935 """
1936 Returns how many margins are currently defined.
1937 """
1938 return len(self.indents)
1939
1940 def indent(self, line):
1941 """
1942 Indents a line by the currently defined margin.
1943 """
1944 return self.margin + line
1945
1946 def dedent(self, line):
1947 """
1948 Dedents a line by the currently defined margin.
1949 (The inverse of 'indent'.)
1950 """
1951 margin = self.margin
1952 indent = self.indents[-1]
1953 if not line.startswith(margin):
1954 fail('Cannot dedent, line does not start with the previous margin:')
1955 return line[indent:]
1956
1957
1958class DSLParser:
1959 def __init__(self, clinic):
1960 self.clinic = clinic
1961
1962 self.directives = {}
1963 for name in dir(self):
1964 # functions that start with directive_ are added to directives
1965 _, s, key = name.partition("directive_")
1966 if s:
1967 self.directives[key] = getattr(self, name)
1968
1969 # functions that start with at_ are too, with an @ in front
1970 _, s, key = name.partition("at_")
1971 if s:
1972 self.directives['@' + key] = getattr(self, name)
1973
1974 self.reset()
1975
1976 def reset(self):
1977 self.function = None
1978 self.state = self.state_dsl_start
1979 self.parameter_indent = None
1980 self.keyword_only = False
1981 self.group = 0
1982 self.parameter_state = self.ps_start
1983 self.indent = IndentStack()
1984 self.kind = CALLABLE
1985 self.coexist = False
1986
Larry Hastingsebdcb502013-11-23 14:54:00 -08001987 def directive_version(self, required):
1988 global version
1989 if version_comparitor(version, required) < 0:
1990 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
1991
Larry Hastings31826802013-10-19 00:09:25 -07001992 def directive_module(self, name):
1993 fields = name.split('.')
1994 new = fields.pop()
1995 module, cls = self.clinic._module_and_class(fields)
1996 if cls:
1997 fail("Can't nest a module inside a class!")
1998 m = Module(name, module)
1999 module.modules[name] = m
2000 self.block.signatures.append(m)
2001
2002 def directive_class(self, name):
2003 fields = name.split('.')
2004 in_classes = False
2005 parent = self
2006 name = fields.pop()
2007 so_far = []
2008 module, cls = self.clinic._module_and_class(fields)
2009
Larry Hastings31826802013-10-19 00:09:25 -07002010 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002011 if cls:
2012 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002013 else:
2014 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002015 self.block.signatures.append(c)
2016
2017 def at_classmethod(self):
2018 assert self.kind is CALLABLE
2019 self.kind = CLASS_METHOD
2020
2021 def at_staticmethod(self):
2022 assert self.kind is CALLABLE
2023 self.kind = STATIC_METHOD
2024
2025 def at_coexist(self):
2026 assert self.coexist == False
2027 self.coexist = True
2028
Larry Hastingsebdcb502013-11-23 14:54:00 -08002029
Larry Hastings31826802013-10-19 00:09:25 -07002030 def parse(self, block):
2031 self.reset()
2032 self.block = block
2033 block_start = self.clinic.block_parser.line_number
2034 lines = block.input.split('\n')
2035 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2036 if '\t' in line:
2037 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2038 self.state(line)
2039
2040 self.next(self.state_terminal)
2041 self.state(None)
2042
2043 block.output = self.clinic.language.render(block.signatures)
2044
2045 @staticmethod
2046 def ignore_line(line):
2047 # ignore comment-only lines
2048 if line.lstrip().startswith('#'):
2049 return True
2050
2051 # Ignore empty lines too
2052 # (but not in docstring sections!)
2053 if not line.strip():
2054 return True
2055
2056 return False
2057
2058 @staticmethod
2059 def calculate_indent(line):
2060 return len(line) - len(line.strip())
2061
2062 def next(self, state, line=None):
2063 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2064 self.state = state
2065 if line is not None:
2066 self.state(line)
2067
2068 def state_dsl_start(self, line):
2069 # self.block = self.ClinicOutputBlock(self)
2070 if self.ignore_line(line):
2071 return
2072 self.next(self.state_modulename_name, line)
2073
2074 def state_modulename_name(self, line):
2075 # looking for declaration, which establishes the leftmost column
2076 # line should be
2077 # modulename.fnname [as c_basename] [-> return annotation]
2078 # square brackets denote optional syntax.
2079 #
2080 # (but we might find a directive first!)
2081 #
2082 # this line is permitted to start with whitespace.
2083 # we'll call this number of spaces F (for "function").
2084
2085 if not line.strip():
2086 return
2087
2088 self.indent.infer(line)
2089
2090 # is it a directive?
2091 fields = shlex.split(line)
2092 directive_name = fields[0]
2093 directive = self.directives.get(directive_name, None)
2094 if directive:
2095 directive(*fields[1:])
2096 return
2097
2098 line, _, returns = line.partition('->')
2099
2100 full_name, _, c_basename = line.partition(' as ')
2101 full_name = full_name.strip()
2102 c_basename = c_basename.strip() or None
2103
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002104 if not is_legal_py_identifier(full_name):
2105 fail("Illegal function name: {}".format(full_name))
2106 if c_basename and not is_legal_c_identifier(c_basename):
2107 fail("Illegal C basename: {}".format(c_basename))
2108
Larry Hastings31826802013-10-19 00:09:25 -07002109 if not returns:
2110 return_converter = CReturnConverter()
2111 else:
2112 ast_input = "def x() -> {}: pass".format(returns)
2113 module = None
2114 try:
2115 module = ast.parse(ast_input)
2116 except SyntaxError:
2117 pass
2118 if not module:
2119 fail("Badly-formed annotation for " + full_name + ": " + returns)
2120 try:
2121 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
2122 assert not legacy
2123 if name not in return_converters:
2124 fail("Error: No available return converter called " + repr(name))
2125 return_converter = return_converters[name](**kwargs)
2126 except ValueError:
2127 fail("Badly-formed annotation for " + full_name + ": " + returns)
2128
2129 fields = [x.strip() for x in full_name.split('.')]
2130 function_name = fields.pop()
2131 module, cls = self.clinic._module_and_class(fields)
2132
2133 if not module:
2134 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2135 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2136 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2137 self.block.signatures.append(self.function)
2138 self.next(self.state_parameters_start)
2139
2140 # Now entering the parameters section. The rules, formally stated:
2141 #
2142 # * All lines must be indented with spaces only.
2143 # * The first line must be a parameter declaration.
2144 # * The first line must be indented.
2145 # * This first line establishes the indent for parameters.
2146 # * We'll call this number of spaces P (for "parameter").
2147 # * Thenceforth:
2148 # * Lines indented with P spaces specify a parameter.
2149 # * Lines indented with > P spaces are docstrings for the previous
2150 # parameter.
2151 # * We'll call this number of spaces D (for "docstring").
2152 # * All subsequent lines indented with >= D spaces are stored as
2153 # part of the per-parameter docstring.
2154 # * All lines will have the first D spaces of the indent stripped
2155 # before they are stored.
2156 # * It's illegal to have a line starting with a number of spaces X
2157 # such that P < X < D.
2158 # * A line with < P spaces is the first line of the function
2159 # docstring, which ends processing for parameters and per-parameter
2160 # docstrings.
2161 # * The first line of the function docstring must be at the same
2162 # indent as the function declaration.
2163 # * It's illegal to have any line in the parameters section starting
2164 # with X spaces such that F < X < P. (As before, F is the indent
2165 # of the function declaration.)
2166 #
2167 ##############
2168 #
2169 # Also, currently Argument Clinic places the following restrictions on groups:
2170 # * Each group must contain at least one parameter.
2171 # * Each group may contain at most one group, which must be the furthest
2172 # thing in the group from the required parameters. (The nested group
2173 # must be the first in the group when it's before the required
2174 # parameters, and the last thing in the group when after the required
2175 # parameters.)
2176 # * There may be at most one (top-level) group to the left or right of
2177 # the required parameters.
2178 # * You must specify a slash, and it must be after all parameters.
2179 # (In other words: either all parameters are positional-only,
2180 # or none are.)
2181 #
2182 # Said another way:
2183 # * Each group must contain at least one parameter.
2184 # * All left square brackets before the required parameters must be
2185 # consecutive. (You can't have a left square bracket followed
2186 # by a parameter, then another left square bracket. You can't
2187 # have a left square bracket, a parameter, a right square bracket,
2188 # and then a left square bracket.)
2189 # * All right square brackets after the required parameters must be
2190 # consecutive.
2191 #
2192 # These rules are enforced with a single state variable:
2193 # "parameter_state". (Previously the code was a miasma of ifs and
2194 # separate boolean state variables.) The states are:
2195 #
2196 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2197 # 01 2 3 4 5 6 <- state transitions
2198 #
2199 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2200 # 1: ps_left_square_before. left square brackets before required parameters.
2201 # 2: ps_group_before. in a group, before required parameters.
2202 # 3: ps_required. required parameters. (renumber left groups!)
2203 # 4: ps_group_after. in a group, after required parameters.
2204 # 5: ps_right_square_after. right square brackets after required parameters.
2205 # 6: ps_seen_slash. seen slash.
2206 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2207 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2208
2209 def state_parameters_start(self, line):
2210 if self.ignore_line(line):
2211 return
2212
2213 # if this line is not indented, we have no parameters
2214 if not self.indent.infer(line):
2215 return self.next(self.state_function_docstring, line)
2216
2217 return self.next(self.state_parameter, line)
2218
2219
2220 def to_required(self):
2221 """
2222 Transition to the "required" parameter state.
2223 """
2224 if self.parameter_state != self.ps_required:
2225 self.parameter_state = self.ps_required
2226 for p in self.function.parameters.values():
2227 p.group = -p.group
2228
2229 def state_parameter(self, line):
2230 if self.ignore_line(line):
2231 return
2232
2233 assert self.indent.depth == 2
2234 indent = self.indent.infer(line)
2235 if indent == -1:
2236 # we outdented, must be to definition column
2237 return self.next(self.state_function_docstring, line)
2238
2239 if indent == 1:
2240 # we indented, must be to new parameter docstring column
2241 return self.next(self.state_parameter_docstring_start, line)
2242
2243 line = line.lstrip()
2244
2245 if line in ('*', '/', '[', ']'):
2246 self.parse_special_symbol(line)
2247 return
2248
2249 if self.parameter_state in (self.ps_start, self.ps_required):
2250 self.to_required()
2251 elif self.parameter_state == self.ps_left_square_before:
2252 self.parameter_state = self.ps_group_before
2253 elif self.parameter_state == self.ps_group_before:
2254 if not self.group:
2255 self.to_required()
2256 elif self.parameter_state == self.ps_group_after:
2257 pass
2258 else:
2259 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2260
2261 ast_input = "def x({}): pass".format(line)
2262 module = None
2263 try:
2264 module = ast.parse(ast_input)
2265 except SyntaxError:
2266 pass
2267 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07002268 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07002269
2270 function_args = module.body[0].args
2271 parameter = function_args.args[0]
2272
2273 if function_args.defaults:
2274 expr = function_args.defaults[0]
2275 # mild hack: explicitly support NULL as a default value
2276 if isinstance(expr, ast.Name) and expr.id == 'NULL':
2277 value = NULL
2278 else:
2279 value = ast.literal_eval(expr)
2280 else:
2281 value = unspecified
2282
2283 parameter_name = parameter.arg
2284 name, legacy, kwargs = self.parse_converter(parameter.annotation)
2285 dict = legacy_converters if legacy else converters
2286 legacy_str = "legacy " if legacy else ""
2287 if name not in dict:
2288 fail('{} is not a valid {}converter'.format(name, legacy_str))
2289 converter = dict[name](parameter_name, self.function, value, **kwargs)
2290
Larry Hastingsebdcb502013-11-23 14:54:00 -08002291 # special case: if it's the self converter,
2292 # don't actually add it to the parameter list
2293 if isinstance(converter, self_converter):
2294 if self.function.parameters or (self.parameter_state != self.ps_required):
2295 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
2296 if self.function.self_converter:
2297 fail("You can't specify the 'self' parameter more than once.")
2298 self.function.self_converter = converter
2299 self.parameter_state = self.ps_start
2300 return
2301
Larry Hastings31826802013-10-19 00:09:25 -07002302 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
2303 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
2304 self.function.parameters[parameter_name] = p
2305
2306 def parse_converter(self, annotation):
2307 if isinstance(annotation, ast.Str):
2308 return annotation.s, True, {}
2309
2310 if isinstance(annotation, ast.Name):
2311 return annotation.id, False, {}
2312
2313 assert isinstance(annotation, ast.Call)
2314
2315 name = annotation.func.id
2316 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
2317 return name, False, kwargs
2318
2319 def parse_special_symbol(self, symbol):
2320 if self.parameter_state == self.ps_seen_slash:
2321 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
2322
2323 if symbol == '*':
2324 if self.keyword_only:
2325 fail("Function " + self.function.name + " uses '*' more than once.")
2326 self.keyword_only = True
2327 elif symbol == '[':
2328 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
2329 self.parameter_state = self.ps_left_square_before
2330 elif self.parameter_state in (self.ps_required, self.ps_group_after):
2331 self.parameter_state = self.ps_group_after
2332 else:
2333 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2334 self.group += 1
2335 elif symbol == ']':
2336 if not self.group:
2337 fail("Function " + self.function.name + " has a ] without a matching [.")
2338 if not any(p.group == self.group for p in self.function.parameters.values()):
2339 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
2340 self.group -= 1
2341 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
2342 self.parameter_state = self.ps_group_before
2343 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
2344 self.parameter_state = self.ps_right_square_after
2345 else:
2346 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2347 elif symbol == '/':
2348 # ps_required is allowed here, that allows positional-only without option groups
2349 # to work (and have default values!)
2350 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
2351 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2352 if self.keyword_only:
2353 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2354 self.parameter_state = self.ps_seen_slash
2355 # fixup preceeding parameters
2356 for p in self.function.parameters.values():
2357 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
2358 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2359 p.kind = inspect.Parameter.POSITIONAL_ONLY
2360
2361 def state_parameter_docstring_start(self, line):
2362 self.parameter_docstring_indent = len(self.indent.margin)
2363 assert self.indent.depth == 3
2364 return self.next(self.state_parameter_docstring, line)
2365
2366 # every line of the docstring must start with at least F spaces,
2367 # where F > P.
2368 # these F spaces will be stripped.
2369 def state_parameter_docstring(self, line):
2370 stripped = line.strip()
2371 if stripped.startswith('#'):
2372 return
2373
2374 indent = self.indent.measure(line)
2375 if indent < self.parameter_docstring_indent:
2376 self.indent.infer(line)
2377 assert self.indent.depth < 3
2378 if self.indent.depth == 2:
2379 # back to a parameter
2380 return self.next(self.state_parameter, line)
2381 assert self.indent.depth == 1
2382 return self.next(self.state_function_docstring, line)
2383
2384 assert self.function.parameters
2385 last_parameter = next(reversed(list(self.function.parameters.values())))
2386
2387 new_docstring = last_parameter.docstring
2388
2389 if new_docstring:
2390 new_docstring += '\n'
2391 if stripped:
2392 new_docstring += self.indent.dedent(line)
2393
2394 last_parameter.docstring = new_docstring
2395
2396 # the final stanza of the DSL is the docstring.
2397 def state_function_docstring(self, line):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002398 if not self.function.self_converter:
2399 self.function.self_converter = self_converter("self", self.function)
2400
Larry Hastings31826802013-10-19 00:09:25 -07002401 if self.group:
2402 fail("Function " + self.function.name + " has a ] without a matching [.")
2403
2404 stripped = line.strip()
2405 if stripped.startswith('#'):
2406 return
2407
2408 new_docstring = self.function.docstring
2409 if new_docstring:
2410 new_docstring += "\n"
2411 if stripped:
2412 line = self.indent.dedent(line).rstrip()
2413 else:
2414 line = ''
2415 new_docstring += line
2416 self.function.docstring = new_docstring
2417
2418 def format_docstring(self):
2419 f = self.function
2420
2421 add, output = text_accumulator()
2422 parameters = list(f.parameters.values())
2423
2424 ##
2425 ## docstring first line
2426 ##
2427
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002428 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07002429 add('(')
2430
2431 # populate "right_bracket_count" field for every parameter
2432 if parameters:
2433 # for now, the only way Clinic supports positional-only parameters
2434 # is if all of them are positional-only.
2435 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
2436 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
2437 assert all(positional_only_parameters)
2438 for p in parameters:
2439 p.right_bracket_count = abs(p.group)
2440 else:
2441 # don't put any right brackets around non-positional-only parameters, ever.
2442 for p in parameters:
2443 p.right_bracket_count = 0
2444
2445 right_bracket_count = 0
2446
2447 def fix_right_bracket_count(desired):
2448 nonlocal right_bracket_count
2449 s = ''
2450 while right_bracket_count < desired:
2451 s += '['
2452 right_bracket_count += 1
2453 while right_bracket_count > desired:
2454 s += ']'
2455 right_bracket_count -= 1
2456 return s
2457
2458 added_star = False
2459 add_comma = False
2460
2461 for p in parameters:
2462 assert p.name
2463
2464 if p.is_keyword_only() and not added_star:
2465 added_star = True
2466 if add_comma:
2467 add(', ')
2468 add('*')
2469
2470 a = [p.name]
2471 if p.converter.is_optional():
2472 a.append('=')
2473 value = p.converter.default
2474 a.append(p.converter.doc_default)
2475 s = fix_right_bracket_count(p.right_bracket_count)
2476 s += "".join(a)
2477 if add_comma:
2478 add(', ')
2479 add(s)
2480 add_comma = True
2481
2482 add(fix_right_bracket_count(0))
2483 add(')')
2484
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002485 # if f.return_converter.doc_default:
2486 # add(' -> ')
2487 # add(f.return_converter.doc_default)
Larry Hastings31826802013-10-19 00:09:25 -07002488
2489 docstring_first_line = output()
2490
2491 # now fix up the places where the brackets look wrong
2492 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
2493
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002494 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07002495 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002496 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07002497 for p in parameters:
2498 if not p.docstring.strip():
2499 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002500 if spacer_line:
2501 add('\n')
2502 else:
2503 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07002504 add(" ")
2505 add(p.name)
2506 add('\n')
2507 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002508 parameters = output()
2509 if parameters:
2510 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07002511
2512 ##
2513 ## docstring body
2514 ##
2515
2516 docstring = f.docstring.rstrip()
2517 lines = [line.rstrip() for line in docstring.split('\n')]
2518
2519 # Enforce the summary line!
2520 # The first line of a docstring should be a summary of the function.
2521 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
2522 # by itself.
2523 #
2524 # Argument Clinic enforces the following rule:
2525 # * either the docstring is empty,
2526 # * or it must have a summary line.
2527 #
2528 # Guido said Clinic should enforce this:
2529 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
2530
2531 if len(lines) >= 2:
2532 if lines[1]:
2533 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
2534 "Every non-blank function docstring must start with\n" +
2535 "a single line summary followed by an empty line.")
2536 elif len(lines) == 1:
2537 # the docstring is only one line right now--the summary line.
2538 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002539 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07002540 lines.append('')
2541
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002542 parameters_marker_count = len(docstring.split('{parameters}')) - 1
2543 if parameters_marker_count > 1:
2544 fail('You may not specify {parameters} more than once in a docstring!')
2545
2546 if not parameters_marker_count:
2547 # insert after summary line
2548 lines.insert(2, '{parameters}')
2549
2550 # insert at front of docstring
2551 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07002552
2553 docstring = "\n".join(lines)
2554
2555 add(docstring)
2556 docstring = output()
2557
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002558 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07002559 docstring = docstring.rstrip()
2560
2561 return docstring
2562
2563 def state_terminal(self, line):
2564 """
2565 Called when processing the block is done.
2566 """
2567 assert not line
2568
2569 if not self.function:
2570 return
2571
2572 if self.keyword_only:
2573 values = self.function.parameters.values()
2574 if not values:
2575 no_parameter_after_star = True
2576 else:
2577 last_parameter = next(reversed(list(values)))
2578 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
2579 if no_parameter_after_star:
2580 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
2581
2582 # remove trailing whitespace from all parameter docstrings
2583 for name, value in self.function.parameters.items():
2584 if not value:
2585 continue
2586 value.docstring = value.docstring.rstrip()
2587
2588 self.function.docstring = self.format_docstring()
2589
2590
2591# maps strings to callables.
2592# the callable should return an object
2593# that implements the clinic parser
2594# interface (__init__ and parse).
2595#
2596# example parsers:
2597# "clinic", handles the Clinic DSL
2598# "python", handles running Python code
2599#
2600parsers = {'clinic' : DSLParser, 'python': PythonParser}
2601
2602
2603clinic = None
2604
2605
2606def main(argv):
2607 import sys
2608
2609 if sys.version_info.major < 3 or sys.version_info.minor < 3:
2610 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
2611
2612 import argparse
2613 cmdline = argparse.ArgumentParser()
2614 cmdline.add_argument("-f", "--force", action='store_true')
2615 cmdline.add_argument("-o", "--output", type=str)
2616 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002617 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07002618 cmdline.add_argument("filename", type=str, nargs="*")
2619 ns = cmdline.parse_args(argv)
2620
2621 if ns.converters:
2622 if ns.filename:
2623 print("Usage error: can't specify --converters and a filename at the same time.")
2624 print()
2625 cmdline.print_usage()
2626 sys.exit(-1)
2627 converters = []
2628 return_converters = []
2629 ignored = set("""
2630 add_c_converter
2631 add_c_return_converter
2632 add_default_legacy_c_converter
2633 add_legacy_c_converter
2634 """.strip().split())
2635 module = globals()
2636 for name in module:
2637 for suffix, ids in (
2638 ("_return_converter", return_converters),
2639 ("_converter", converters),
2640 ):
2641 if name in ignored:
2642 continue
2643 if name.endswith(suffix):
2644 ids.append((name, name[:-len(suffix)]))
2645 break
2646 print()
2647
2648 print("Legacy converters:")
2649 legacy = sorted(legacy_converters)
2650 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
2651 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
2652 print()
2653
2654 for title, attribute, ids in (
2655 ("Converters", 'converter_init', converters),
2656 ("Return converters", 'return_converter_init', return_converters),
2657 ):
2658 print(title + ":")
2659 longest = -1
2660 for name, short_name in ids:
2661 longest = max(longest, len(short_name))
2662 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
2663 cls = module[name]
2664 callable = getattr(cls, attribute, None)
2665 if not callable:
2666 continue
2667 signature = inspect.signature(callable)
2668 parameters = []
2669 for parameter_name, parameter in signature.parameters.items():
2670 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2671 if parameter.default != inspect.Parameter.empty:
2672 s = '{}={!r}'.format(parameter_name, parameter.default)
2673 else:
2674 s = parameter_name
2675 parameters.append(s)
2676 print(' {}({})'.format(short_name, ', '.join(parameters)))
2677 # add_comma = False
2678 # for parameter_name, parameter in signature.parameters.items():
2679 # if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2680 # if add_comma:
2681 # parameters.append(', ')
2682 # else:
2683 # add_comma = True
2684 # s = parameter_name
2685 # if parameter.default != inspect.Parameter.empty:
2686 # s += '=' + repr(parameter.default)
2687 # parameters.append(s)
2688 # parameters.append(')')
2689
2690 # print(" ", short_name + "".join(parameters))
2691 print()
2692 print("All converters also accept (doc_default=None, required=False).")
2693 print("All return converters also accept (doc_default=None).")
2694 sys.exit(0)
2695
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002696 if ns.make:
2697 if ns.output or ns.filename:
2698 print("Usage error: can't use -o or filenames with --make.")
2699 print()
2700 cmdline.print_usage()
2701 sys.exit(-1)
2702 for root, dirs, files in os.walk('.'):
2703 for rcs_dir in ('.svn', '.git', '.hg'):
2704 if rcs_dir in dirs:
2705 dirs.remove(rcs_dir)
2706 for filename in files:
2707 if not filename.endswith('.c'):
2708 continue
2709 path = os.path.join(root, filename)
2710 parse_file(path, verify=not ns.force)
2711 return
2712
Larry Hastings31826802013-10-19 00:09:25 -07002713 if not ns.filename:
2714 cmdline.print_usage()
2715 sys.exit(-1)
2716
2717 if ns.output and len(ns.filename) > 1:
2718 print("Usage error: can't use -o with multiple filenames.")
2719 print()
2720 cmdline.print_usage()
2721 sys.exit(-1)
2722
2723 for filename in ns.filename:
2724 parse_file(filename, output=ns.output, verify=not ns.force)
2725
2726
2727if __name__ == "__main__":
2728 sys.exit(main(sys.argv[1:]))