blob: a68551f6a6d0c782b89079f488e603b46e8eaa19 [file] [log] [blame]
Larry Hastings31826802013-10-19 00:09:25 -07001#!/usr/bin/env python3
2#
3# Argument Clinic
4# Copyright 2012-2013 by Larry Hastings.
5# Licensed to the PSF under a contributor agreement.
6#
7
8import abc
9import ast
10import atexit
Larry Hastings31826802013-10-19 00:09:25 -070011import collections
12import contextlib
13import functools
14import hashlib
15import inspect
16import io
17import itertools
18import os
Larry Hastingsbebf7352014-01-17 17:47:17 -080019import pprint
Larry Hastings31826802013-10-19 00:09:25 -070020import re
21import shlex
Larry Hastings581ee362014-01-28 05:00:08 -080022import string
Larry Hastings31826802013-10-19 00:09:25 -070023import sys
24import tempfile
25import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010026import traceback
Larry Hastingsbebf7352014-01-17 17:47:17 -080027import uuid
Larry Hastings31826802013-10-19 00:09:25 -070028
Larry Hastings31826802013-10-19 00:09:25 -070029# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070030#
31# soon:
32#
33# * allow mixing any two of {positional-only, positional-or-keyword,
34# keyword-only}
35# * dict constructor uses positional-only and keyword-only
36# * max and min use positional only with an optional group
37# and keyword-only
38#
Larry Hastings31826802013-10-19 00:09:25 -070039
Larry Hastingsebdcb502013-11-23 14:54:00 -080040version = '1'
41
Larry Hastings31826802013-10-19 00:09:25 -070042_empty = inspect._empty
43_void = inspect._void
44
Larry Hastings4a55fc52014-01-12 11:09:57 -080045NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070046
47class Unspecified:
48 def __repr__(self):
49 return '<Unspecified>'
50
51unspecified = Unspecified()
52
53
54class Null:
55 def __repr__(self):
56 return '<Null>'
57
58NULL = Null()
59
60
Larry Hastings2a727912014-01-16 11:32:01 -080061class Unknown:
62 def __repr__(self):
63 return '<Unknown>'
64
65unknown = Unknown()
66
67
Larry Hastings31826802013-10-19 00:09:25 -070068def _text_accumulator():
69 text = []
70 def output():
71 s = ''.join(text)
72 text.clear()
73 return s
74 return text, text.append, output
75
76
77def text_accumulator():
78 """
79 Creates a simple text accumulator / joiner.
80
81 Returns a pair of callables:
82 append, output
83 "append" appends a string to the accumulator.
84 "output" returns the contents of the accumulator
85 joined together (''.join(accumulator)) and
86 empties the accumulator.
87 """
88 text, append, output = _text_accumulator()
89 return append, output
90
91
Larry Hastingsbebf7352014-01-17 17:47:17 -080092def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -070093 joined = " ".join([str(a) for a in args])
94 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -080095 if fail:
96 add("Error")
97 else:
98 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -070099 if clinic:
100 if filename is None:
101 filename = clinic.filename
Larry Hastings581ee362014-01-28 05:00:08 -0800102 if getattr(clinic, 'block_parser', None) and (line_number is None):
Larry Hastings31826802013-10-19 00:09:25 -0700103 line_number = clinic.block_parser.line_number
104 if filename is not None:
105 add(' in file "' + filename + '"')
106 if line_number is not None:
107 add(" on line " + str(line_number))
108 add(':\n')
109 add(joined)
110 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800111 if fail:
112 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700113
114
Larry Hastingsbebf7352014-01-17 17:47:17 -0800115def warn(*args, filename=None, line_number=None):
116 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
117
118def fail(*args, filename=None, line_number=None):
119 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
120
Larry Hastings31826802013-10-19 00:09:25 -0700121
122def quoted_for_c_string(s):
123 for old, new in (
Zachary Ware9d7849f2014-01-25 03:26:20 -0600124 ('\\', '\\\\'), # must be first!
Larry Hastings31826802013-10-19 00:09:25 -0700125 ('"', '\\"'),
126 ("'", "\\'"),
127 ):
128 s = s.replace(old, new)
129 return s
130
Larry Hastings4903e002014-01-18 00:26:16 -0800131def c_repr(s):
132 return '"' + s + '"'
133
134
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700135is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
136
137def is_legal_py_identifier(s):
138 return all(is_legal_c_identifier(field) for field in s.split('.'))
139
Larry Hastingsbebf7352014-01-17 17:47:17 -0800140# identifiers that are okay in Python but aren't a good idea in C.
141# so if they're used Argument Clinic will add "_value" to the end
142# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700143c_keywords = set("""
Larry Hastings5c661892014-01-24 06:17:25 -0800144asm auto break case char const continue default do double
145else enum extern float for goto if inline int long
146register return short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800147typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700148""".strip().split())
149
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700150def ensure_legal_c_identifier(s):
151 # for now, just complain if what we're given isn't legal
152 if not is_legal_c_identifier(s):
153 fail("Illegal C identifier: {}".format(s))
154 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700155 if s in c_keywords:
156 return s + "_value"
157 return s
158
159def rstrip_lines(s):
160 text, add, output = _text_accumulator()
161 for line in s.split('\n'):
162 add(line.rstrip())
163 add('\n')
164 text.pop()
165 return output()
166
167def linear_format(s, **kwargs):
168 """
169 Perform str.format-like substitution, except:
170 * The strings substituted must be on lines by
171 themselves. (This line is the "source line".)
172 * If the substitution text is empty, the source line
173 is removed in the output.
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800174 * If the field is not recognized, the original line
175 is passed unmodified through to the output.
Larry Hastings31826802013-10-19 00:09:25 -0700176 * If the substitution text is not empty:
177 * Each line of the substituted text is indented
178 by the indent of the source line.
179 * A newline will be added to the end.
180 """
181
182 add, output = text_accumulator()
183 for line in s.split('\n'):
184 indent, curly, trailing = line.partition('{')
185 if not curly:
186 add(line)
187 add('\n')
188 continue
189
190 name, curl, trailing = trailing.partition('}')
191 if not curly or name not in kwargs:
192 add(line)
193 add('\n')
194 continue
195
196 if trailing:
197 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
198 if indent.strip():
199 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
200
201 value = kwargs[name]
202 if not value:
203 continue
204
205 value = textwrap.indent(rstrip_lines(value), indent)
206 add(value)
207 add('\n')
208
209 return output()[:-1]
210
Larry Hastingsbebf7352014-01-17 17:47:17 -0800211def indent_all_lines(s, prefix):
212 """
213 Returns 's', with 'prefix' prepended to all lines.
214
215 If the last line is empty, prefix is not prepended
216 to it. (If s is blank, returns s unchanged.)
217
218 (textwrap.indent only adds to non-blank lines.)
219 """
220 split = s.split('\n')
221 last = split.pop()
222 final = []
223 for line in split:
224 final.append(prefix)
225 final.append(line)
226 final.append('\n')
227 if last:
228 final.append(prefix)
229 final.append(last)
230 return ''.join(final)
231
232def suffix_all_lines(s, suffix):
233 """
234 Returns 's', with 'suffix' appended to all lines.
235
236 If the last line is empty, suffix is not appended
237 to it. (If s is blank, returns s unchanged.)
238 """
239 split = s.split('\n')
240 last = split.pop()
241 final = []
242 for line in split:
243 final.append(line)
244 final.append(suffix)
245 final.append('\n')
246 if last:
247 final.append(last)
248 final.append(suffix)
249 return ''.join(final)
250
251
Larry Hastingsebdcb502013-11-23 14:54:00 -0800252def version_splitter(s):
253 """Splits a version string into a tuple of integers.
254
255 The following ASCII characters are allowed, and employ
256 the following conversions:
257 a -> -3
258 b -> -2
259 c -> -1
260 (This permits Python-style version strings such as "1.4b3".)
261 """
262 version = []
263 accumulator = []
264 def flush():
265 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800266 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800267 version.append(int(''.join(accumulator)))
268 accumulator.clear()
269
270 for c in s:
271 if c.isdigit():
272 accumulator.append(c)
273 elif c == '.':
274 flush()
275 elif c in 'abc':
276 flush()
277 version.append('abc'.index(c) - 3)
278 else:
279 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
280 flush()
281 return tuple(version)
282
283def version_comparitor(version1, version2):
284 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
285 for i, (a, b) in enumerate(iterator):
286 if a < b:
287 return -1
288 if a > b:
289 return 1
290 return 0
291
Larry Hastings31826802013-10-19 00:09:25 -0700292
293class CRenderData:
294 def __init__(self):
295
296 # The C statements to declare variables.
297 # Should be full lines with \n eol characters.
298 self.declarations = []
299
300 # The C statements required to initialize the variables before the parse call.
301 # Should be full lines with \n eol characters.
302 self.initializers = []
303
Larry Hastingsc2047262014-01-25 20:43:29 -0800304 # The C statements needed to dynamically modify the values
305 # parsed by the parse call, before calling the impl.
306 self.modifications = []
307
Larry Hastings31826802013-10-19 00:09:25 -0700308 # The entries for the "keywords" array for PyArg_ParseTuple.
309 # Should be individual strings representing the names.
310 self.keywords = []
311
312 # The "format units" for PyArg_ParseTuple.
313 # Should be individual strings that will get
314 self.format_units = []
315
316 # The varargs arguments for PyArg_ParseTuple.
317 self.parse_arguments = []
318
319 # The parameter declarations for the impl function.
320 self.impl_parameters = []
321
322 # The arguments to the impl function at the time it's called.
323 self.impl_arguments = []
324
325 # For return converters: the name of the variable that
326 # should receive the value returned by the impl.
327 self.return_value = "return_value"
328
329 # For return converters: the code to convert the return
330 # value from the parse function. This is also where
331 # you should check the _return_value for errors, and
332 # "goto exit" if there are any.
333 self.return_conversion = []
334
335 # The C statements required to clean up after the impl call.
336 self.cleanup = []
337
338
Larry Hastings581ee362014-01-28 05:00:08 -0800339class FormatCounterFormatter(string.Formatter):
340 """
341 This counts how many instances of each formatter
342 "replacement string" appear in the format string.
343
344 e.g. after evaluating "string {a}, {b}, {c}, {a}"
345 the counts dict would now look like
346 {'a': 2, 'b': 1, 'c': 1}
347 """
348 def __init__(self):
349 self.counts = collections.Counter()
350
351 def get_value(self, key, args, kwargs):
352 self.counts[key] += 1
353 return ''
354
Larry Hastings31826802013-10-19 00:09:25 -0700355class Language(metaclass=abc.ABCMeta):
356
357 start_line = ""
358 body_prefix = ""
359 stop_line = ""
360 checksum_line = ""
361
362 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800363 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700364 pass
365
366 def validate(self):
Larry Hastings581ee362014-01-28 05:00:08 -0800367 def assert_only_one(attr, *additional_fields):
368 """
369 Ensures that the string found at getattr(self, attr)
370 contains exactly one formatter replacement string for
371 each valid field. The list of valid fields is
372 ['dsl_name'] extended by additional_fields.
373
374 e.g.
375 self.fmt = "{dsl_name} {a} {b}"
376
377 # this passes
378 self.assert_only_one('fmt', 'a', 'b')
379
380 # this fails, the format string has a {b} in it
381 self.assert_only_one('fmt', 'a')
382
383 # this fails, the format string doesn't have a {c} in it
384 self.assert_only_one('fmt', 'a', 'b', 'c')
385
386 # this fails, the format string has two {a}s in it,
387 # it must contain exactly one
388 self.fmt2 = '{dsl_name} {a} {a}'
389 self.assert_only_one('fmt2', 'a')
390
391 """
392 fields = ['dsl_name']
393 fields.extend(additional_fields)
394 line = getattr(self, attr)
395 fcf = FormatCounterFormatter()
396 fcf.format(line)
397 def local_fail(should_be_there_but_isnt):
398 if should_be_there_but_isnt:
399 fail("{} {} must contain {{{}}} exactly once!".format(
400 self.__class__.__name__, attr, name))
401 else:
402 fail("{} {} must not contain {{{}}}!".format(
403 self.__class__.__name__, attr, name))
404
405 for name, count in fcf.counts.items():
406 if name in fields:
407 if count > 1:
408 local_fail(True)
409 else:
410 local_fail(False)
411 for name in fields:
412 if fcf.counts.get(name) != 1:
413 local_fail(True)
414
Larry Hastings31826802013-10-19 00:09:25 -0700415 assert_only_one('start_line')
416 assert_only_one('stop_line')
Larry Hastings31826802013-10-19 00:09:25 -0700417
Larry Hastings581ee362014-01-28 05:00:08 -0800418 field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
419 assert_only_one('checksum_line', field)
Larry Hastings31826802013-10-19 00:09:25 -0700420
421
422
423class PythonLanguage(Language):
424
425 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800426 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700427 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800428 stop_line = "#[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800429 checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700430
431
432def permute_left_option_groups(l):
433 """
434 Given [1, 2, 3], should yield:
435 ()
436 (3,)
437 (2, 3)
438 (1, 2, 3)
439 """
440 yield tuple()
441 accumulator = []
442 for group in reversed(l):
443 accumulator = list(group) + accumulator
444 yield tuple(accumulator)
445
446
447def permute_right_option_groups(l):
448 """
449 Given [1, 2, 3], should yield:
450 ()
451 (1,)
452 (1, 2)
453 (1, 2, 3)
454 """
455 yield tuple()
456 accumulator = []
457 for group in l:
458 accumulator.extend(group)
459 yield tuple(accumulator)
460
461
462def permute_optional_groups(left, required, right):
463 """
464 Generator function that computes the set of acceptable
465 argument lists for the provided iterables of
466 argument groups. (Actually it generates a tuple of tuples.)
467
468 Algorithm: prefer left options over right options.
469
470 If required is empty, left must also be empty.
471 """
472 required = tuple(required)
473 result = []
474
475 if not required:
476 assert not left
477
478 accumulator = []
479 counts = set()
480 for r in permute_right_option_groups(right):
481 for l in permute_left_option_groups(left):
482 t = l + required + r
483 if len(t) in counts:
484 continue
485 counts.add(len(t))
486 accumulator.append(t)
487
488 accumulator.sort(key=len)
489 return tuple(accumulator)
490
491
492class CLanguage(Language):
493
Larry Hastings61272b72014-01-07 12:41:53 -0800494 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700495 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800496 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700497 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800498 stop_line = "[{dsl_name} start generated code]*/"
Larry Hastings581ee362014-01-28 05:00:08 -0800499 checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700500
Larry Hastingsbebf7352014-01-17 17:47:17 -0800501 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700502 function = None
503 for o in signatures:
504 if isinstance(o, Function):
505 if function:
506 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
507 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800508 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700509
510 def docstring_for_c_string(self, f):
511 text, add, output = _text_accumulator()
512 # turn docstring into a properly quoted C string
513 for line in f.docstring.split('\n'):
514 add('"')
515 add(quoted_for_c_string(line))
516 add('\\n"\n')
517
518 text.pop()
519 add('"')
520 return ''.join(text)
521
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800522 _templates = {}
523 # the templates will be run through str.format(),
524 # so actual curly-braces need to be doubled up.
525 templates_source = """
526__________________________________________________
527
528docstring_prototype
529
530PyDoc_VAR({c_basename}__doc__);
531__________________________________________________
532
533docstring_definition
534
535PyDoc_STRVAR({c_basename}__doc__,
536{docstring});
537__________________________________________________
538
539impl_definition
540
541static {impl_return_type}
542{c_basename}_impl({impl_parameters})
543__________________________________________________
544
545parser_prototype_noargs
546
547static PyObject *
548{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
549__________________________________________________
550
551parser_prototype_meth_o
552
553# SLIGHT HACK
554# METH_O uses {impl_parameters} for the parser!
555
556static PyObject *
557{c_basename}({impl_parameters})
558__________________________________________________
559
560parser_prototype_varargs
561
562static PyObject *
563{c_basename}({self_type}{self_name}, PyObject *args)
564__________________________________________________
565
566parser_prototype_keyword
567
568static PyObject *
569{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
570__________________________________________________
571
572parser_prototype_init
573
574static int
575{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
576__________________________________________________
577
578parser_definition_simple_no_parsing
579
580{{
581 return {c_basename}_impl({impl_arguments});
582}}
583__________________________________________________
584
585parser_definition_start
586
587{{
588 {return_value_declaration}
589 {declarations}
590 {initializers}
591{empty line}
592__________________________________________________
593
594parser_definition_end
595
596 {return_conversion}
597
598{exit_label}
599 {cleanup}
600 return return_value;
601}}
602__________________________________________________
603
604parser_definition_impl_call
605
Larry Hastingsc2047262014-01-25 20:43:29 -0800606 {modifications}
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800607 {return_value} = {c_basename}_impl({impl_arguments});
608__________________________________________________
609
610parser_definition_unpack_tuple
611
612 if (!PyArg_UnpackTuple(args, "{name}",
613 {unpack_min}, {unpack_max},
614 {parse_arguments}))
615 goto exit;
616__________________________________________________
617
618parser_definition_parse_tuple
619
620 if (!PyArg_ParseTuple(args,
621 "{format_units}:{name}",
622 {parse_arguments}))
623 goto exit;
624__________________________________________________
625
626parser_definition_option_groups
627 {option_group_parsing}
628
629__________________________________________________
630
631parser_definition_parse_tuple_and_keywords
632
633 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
634 "{format_units}:{name}", _keywords,
635 {parse_arguments}))
636 goto exit;
637__________________________________________________
638
639parser_definition_no_positional
640
Larry Hastingsc2047262014-01-25 20:43:29 -0800641 if ({self_type_check}!_PyArg_NoPositional("{name}", args))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800642 goto exit;
643
644__________________________________________________
645
646parser_definition_no_keywords
647
Larry Hastingsc2047262014-01-25 20:43:29 -0800648 if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs))
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800649 goto exit;
650
651__________________________________________________
652
653methoddef_define
654
655#define {methoddef_name} \\
656 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
657__________________________________________________
658""".rstrip()
659
660 title = ''
661 buffer = []
662 line = None
663 for line in templates_source.split('\n'):
664 line = line.rstrip()
665 if line.startswith('# '):
666 # comment
667 continue
668 if line.startswith("_____"):
669 if not buffer:
670 continue
671 assert title not in _templates, "defined template twice: " + repr(title)
672 buffer = '\n'.join(buffer).rstrip()
673 buffer = buffer.replace('{empty line}', '')
674 _templates[title] = buffer
675 buffer = []
676 title = ''
677 continue
678 if not title:
679 if not line:
680 continue
681 title = line
682 continue
683 if not (line or buffer):
684 # throw away leading blank lines
685 continue
686 buffer.append(line)
687
688 assert not title, 'ensure templates_source ends with ______ (still adding to ' + repr(title) + ")"
689
690 del templates_source
691 del title
692 del buffer
693 del line
694
695 # for name, value in _templates.items():
696 # print(name + ":")
697 # pprint.pprint(value)
698 # print()
Larry Hastings31826802013-10-19 00:09:25 -0700699
Larry Hastingsbebf7352014-01-17 17:47:17 -0800700 def output_templates(self, f):
701 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800702 assert parameters
703 assert isinstance(parameters[0].converter, self_converter)
704 del parameters[0]
Larry Hastingsbebf7352014-01-17 17:47:17 -0800705 converters = [p.converter for p in parameters]
706
707 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
708 default_return_converter = (not f.return_converter or
709 f.return_converter.type == 'PyObject *')
710
711 positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY)
712 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
713 first_optional = len(parameters)
714 for i, p in enumerate(parameters):
715 c = p.converter
716 if type(c) != object_converter:
717 break
718 if c.format_unit != 'O':
719 break
720 if p.default is not unspecified:
721 first_optional = min(first_optional, i)
722 else:
723 all_boring_objects = True
724
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800725 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
726
Larry Hastingsbebf7352014-01-17 17:47:17 -0800727 meth_o = (len(parameters) == 1 and
728 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
729 not converters[0].is_optional() and
730 isinstance(converters[0], object_converter) and
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800731 converters[0].format_unit == 'O' and
732 not new_or_init)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800733
734 # we have to set seven things before we're done:
735 #
736 # docstring_prototype
737 # docstring_definition
738 # impl_prototype
739 # methoddef_define
740 # parser_prototype
741 # parser_definition
742 # impl_definition
Larry Hastingsbebf7352014-01-17 17:47:17 -0800743
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800744 templates = self._templates
Larry Hastingsbebf7352014-01-17 17:47:17 -0800745
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800746 return_value_declaration = "PyObject *return_value = NULL;"
Larry Hastings31826802013-10-19 00:09:25 -0700747
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800748 methoddef_define = templates['methoddef_define']
Larry Hastings5c661892014-01-24 06:17:25 -0800749 if new_or_init and not f.docstring:
750 docstring_prototype = docstring_definition = ''
751 else:
752 docstring_prototype = templates['docstring_prototype']
753 docstring_definition = templates['docstring_definition']
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800754 impl_definition = templates['impl_definition']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800755 impl_prototype = parser_prototype = parser_definition = None
756
Larry Hastingsc2047262014-01-25 20:43:29 -0800757 parser_body_fields = ()
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800758 def parser_body(prototype, *fields):
759 nonlocal parser_body_fields
760 add, output = text_accumulator()
761 add(prototype)
762 parser_body_fields = fields
763 fields = list(fields)
764 fields.insert(0, 'parser_definition_start')
765 fields.append('parser_definition_impl_call')
766 fields.append('parser_definition_end')
767 for field in fields:
768 add('\n')
769 add(templates[field])
770 return output()
Larry Hastingsbebf7352014-01-17 17:47:17 -0800771
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800772 def insert_keywords(s):
773 return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")
Larry Hastingsbebf7352014-01-17 17:47:17 -0800774
775 if not parameters:
776 # no parameters, METH_NOARGS
777
778 flags = "METH_NOARGS"
779
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800780 parser_prototype = templates['parser_prototype_noargs']
781 parser_definition = parser_prototype
Larry Hastingsbebf7352014-01-17 17:47:17 -0800782
783 if default_return_converter:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800784 parser_definition = parser_prototype + '\n' + templates['parser_definition_simple_no_parsing']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800785 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800786 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700787
Larry Hastingsbebf7352014-01-17 17:47:17 -0800788 elif meth_o:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800789 flags = "METH_O"
790 # impl_definition = templates['parser_prototype_meth_o']
791
Larry Hastingsbebf7352014-01-17 17:47:17 -0800792 if default_return_converter:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800793 # maps perfectly to METH_O, doesn't need a return converter.
794 # so we skip making a parse function
795 # and call directly into the impl function.
Larry Hastingsbebf7352014-01-17 17:47:17 -0800796 impl_prototype = parser_prototype = parser_definition = ''
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800797 impl_definition = templates['parser_prototype_meth_o']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800798 else:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800799 parser_prototype = templates['parser_prototype_meth_o']
800 parser_definition = parser_body(parser_prototype)
Larry Hastings31826802013-10-19 00:09:25 -0700801
Larry Hastingsbebf7352014-01-17 17:47:17 -0800802 elif has_option_groups:
803 # positional parameters with option groups
804 # (we have to generate lots of PyArg_ParseTuple calls
805 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700806
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800807 flags = "METH_VARARGS"
808 parser_prototype = templates['parser_prototype_varargs']
Larry Hastings31826802013-10-19 00:09:25 -0700809
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800810 parser_definition = parser_body(parser_prototype, 'parser_definition_option_groups')
Larry Hastings31826802013-10-19 00:09:25 -0700811
Larry Hastingsbebf7352014-01-17 17:47:17 -0800812 elif positional and all_boring_objects:
813 # positional-only, but no option groups,
814 # and nothing but normal objects:
815 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700816
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800817 flags = "METH_VARARGS"
818 parser_prototype = templates['parser_prototype_varargs']
Larry Hastings31826802013-10-19 00:09:25 -0700819
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800820 parser_definition = parser_body(parser_prototype, 'parser_definition_unpack_tuple')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800821
822 elif positional:
823 # positional-only, but no option groups
824 # we only need one call to PyArg_ParseTuple
825
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800826 flags = "METH_VARARGS"
827 parser_prototype = templates['parser_prototype_varargs']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800828
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800829 parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800830
831 else:
832 # positional-or-keyword arguments
833 flags = "METH_VARARGS|METH_KEYWORDS"
834
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800835 parser_prototype = templates['parser_prototype_keyword']
Larry Hastingsbebf7352014-01-17 17:47:17 -0800836
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800837 parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple_and_keywords')
838 parser_definition = insert_keywords(parser_definition)
Larry Hastings31826802013-10-19 00:09:25 -0700839
Larry Hastings31826802013-10-19 00:09:25 -0700840
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800841 if new_or_init:
842 methoddef_define = ''
843
844 if f.kind == METHOD_NEW:
845 parser_prototype = templates['parser_prototype_keyword']
846 else:
847 return_value_declaration = "int return_value = -1;"
848 parser_prototype = templates['parser_prototype_init']
849
850 fields = list(parser_body_fields)
851 parses_positional = 'METH_NOARGS' not in flags
852 parses_keywords = 'METH_KEYWORDS' in flags
853 if parses_keywords:
854 assert parses_positional
855
856 if not parses_keywords:
857 fields.insert(0, 'parser_definition_no_keywords')
858 if not parses_positional:
859 fields.insert(0, 'parser_definition_no_positional')
860
861 parser_definition = parser_body(parser_prototype, *fields)
862 if parses_keywords:
863 parser_definition = insert_keywords(parser_definition)
864
Larry Hastings31826802013-10-19 00:09:25 -0700865
Larry Hastingsbebf7352014-01-17 17:47:17 -0800866 if f.methoddef_flags:
Larry Hastingsbebf7352014-01-17 17:47:17 -0800867 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700868
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800869 methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700870
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800871 # add ';' to the end of parser_prototype and impl_prototype
872 # (they mustn't be None, but they could be an empty string.)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800873 assert parser_prototype is not None
Larry Hastingsbebf7352014-01-17 17:47:17 -0800874 if parser_prototype:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800875 assert not parser_prototype.endswith(';')
Larry Hastingsbebf7352014-01-17 17:47:17 -0800876 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700877
Larry Hastingsbebf7352014-01-17 17:47:17 -0800878 if impl_prototype is None:
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800879 impl_prototype = impl_definition
880 if impl_prototype:
881 impl_prototype += ";"
Larry Hastings31826802013-10-19 00:09:25 -0700882
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800883 parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800884
885 d = {
886 "docstring_prototype" : docstring_prototype,
887 "docstring_definition" : docstring_definition,
888 "impl_prototype" : impl_prototype,
889 "methoddef_define" : methoddef_define,
890 "parser_prototype" : parser_prototype,
891 "parser_definition" : parser_definition,
892 "impl_definition" : impl_definition,
893 }
894
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800895 # make sure we didn't forget to assign something,
896 # and wrap each non-empty value in \n's
Larry Hastingsbebf7352014-01-17 17:47:17 -0800897 d2 = {}
898 for name, value in d.items():
Larry Hastingsb7ccb202014-01-18 23:50:21 -0800899 assert value is not None, "got a None value for template " + repr(name)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800900 if value:
901 value = '\n' + value + '\n'
902 d2[name] = value
903 return d2
Larry Hastings31826802013-10-19 00:09:25 -0700904
905 @staticmethod
906 def group_to_variable_name(group):
907 adjective = "left_" if group < 0 else "right_"
908 return "group_" + adjective + str(abs(group))
909
910 def render_option_group_parsing(self, f, template_dict):
911 # positional only, grouped, optional arguments!
912 # can be optional on the left or right.
913 # here's an example:
914 #
915 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
916 #
917 # Here group D are required, and all other groups are optional.
918 # (Group D's "group" is actually None.)
919 # We can figure out which sets of arguments we have based on
920 # how many arguments are in the tuple.
921 #
922 # Note that you need to count up on both sides. For example,
923 # you could have groups C+D, or C+D+E, or C+D+E+F.
924 #
925 # What if the number of arguments leads us to an ambiguous result?
926 # Clinic prefers groups on the left. So in the above example,
927 # five arguments would map to B+C, not C+D.
928
929 add, output = text_accumulator()
930 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -0800931 if isinstance(parameters[0].converter, self_converter):
932 del parameters[0]
Larry Hastings31826802013-10-19 00:09:25 -0700933
934 groups = []
935 group = None
936 left = []
937 right = []
938 required = []
939 last = unspecified
940
941 for p in parameters:
942 group_id = p.group
943 if group_id != last:
944 last = group_id
945 group = []
946 if group_id < 0:
947 left.append(group)
948 elif group_id == 0:
949 group = required
950 else:
951 right.append(group)
952 group.append(p)
953
954 count_min = sys.maxsize
955 count_max = -1
956
Larry Hastings2a727912014-01-16 11:32:01 -0800957 add("switch (PyTuple_GET_SIZE(args)) {{\n")
Larry Hastings31826802013-10-19 00:09:25 -0700958 for subset in permute_optional_groups(left, required, right):
959 count = len(subset)
960 count_min = min(count_min, count)
961 count_max = max(count_max, count)
962
Larry Hastings583baa82014-01-12 08:49:30 -0800963 if count == 0:
964 add(""" case 0:
965 break;
966""")
967 continue
968
Larry Hastings31826802013-10-19 00:09:25 -0700969 group_ids = {p.group for p in subset} # eliminate duplicates
970 d = {}
971 d['count'] = count
972 d['name'] = f.name
973 d['groups'] = sorted(group_ids)
974 d['format_units'] = "".join(p.converter.format_unit for p in subset)
975
976 parse_arguments = []
977 for p in subset:
978 p.converter.parse_argument(parse_arguments)
979 d['parse_arguments'] = ", ".join(parse_arguments)
980
981 group_ids.discard(0)
982 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
983 lines = "\n".join(lines)
984
985 s = """
986 case {count}:
987 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
Larry Hastings46258262014-01-22 03:05:49 -0800988 goto exit;
Larry Hastings31826802013-10-19 00:09:25 -0700989 {group_booleans}
990 break;
991"""[1:]
992 s = linear_format(s, group_booleans=lines)
993 s = s.format_map(d)
994 add(s)
995
996 add(" default:\n")
997 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
998 add(s.format(f.full_name, count_min, count_max))
Larry Hastings46258262014-01-22 03:05:49 -0800999 add(' goto exit;\n')
Larry Hastings31826802013-10-19 00:09:25 -07001000 add("}}")
1001 template_dict['option_group_parsing'] = output()
1002
Larry Hastingsbebf7352014-01-17 17:47:17 -08001003 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -07001004 if not f:
1005 return ""
1006
1007 add, output = text_accumulator()
1008 data = CRenderData()
1009
Larry Hastings31826802013-10-19 00:09:25 -07001010 parameters = list(f.parameters.values())
Larry Hastings5c661892014-01-24 06:17:25 -08001011 assert parameters, "We should always have a 'self' at this point!"
1012
Larry Hastings31826802013-10-19 00:09:25 -07001013 converters = [p.converter for p in parameters]
1014
Larry Hastings5c661892014-01-24 06:17:25 -08001015 templates = self.output_templates(f)
1016
1017 f_self = parameters[0]
1018 selfless = parameters[1:]
1019 assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!"
1020
1021 last_group = 0
1022 first_optional = len(selfless)
1023 positional = selfless and selfless[-1].kind == inspect.Parameter.POSITIONAL_ONLY
1024 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
1025 default_return_converter = (not f.return_converter or
1026 f.return_converter.type == 'PyObject *')
1027 has_option_groups = False
1028
1029 # offset i by -1 because first_optional needs to ignore self
1030 for i, p in enumerate(parameters, -1):
1031 c = p.converter
1032
1033 if (i != -1) and (p.default is not unspecified):
1034 first_optional = min(first_optional, i)
1035
1036 # insert group variable
1037 group = p.group
1038 if last_group != group:
1039 last_group = group
1040 if group:
1041 group_name = self.group_to_variable_name(group)
1042 data.impl_arguments.append(group_name)
1043 data.declarations.append("int " + group_name + " = 0;")
1044 data.impl_parameters.append("int " + group_name)
1045 has_option_groups = True
1046
1047 c.render(p, data)
1048
1049 if has_option_groups and (not positional):
1050 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
1051
1052 # HACK
1053 # when we're METH_O, but have a custom return converter,
1054 # we use "impl_parameters" for the parsing function
1055 # because that works better. but that means we must
1056 # supress actually declaring the impl's parameters
1057 # as variables in the parsing function. but since it's
1058 # METH_O, we have exactly one anyway, so we know exactly
1059 # where it is.
1060 if ("METH_O" in templates['methoddef_define'] and
1061 not default_return_converter):
1062 data.declarations.pop(0)
1063
Larry Hastings31826802013-10-19 00:09:25 -07001064 template_dict = {}
1065
1066 full_name = f.full_name
1067 template_dict['full_name'] = full_name
1068
Larry Hastings5c661892014-01-24 06:17:25 -08001069 if new_or_init:
1070 name = f.cls.name
1071 else:
1072 name = f.name
1073
Larry Hastings31826802013-10-19 00:09:25 -07001074 template_dict['name'] = name
1075
Larry Hastings8666e652014-01-12 14:12:59 -08001076 if f.c_basename:
1077 c_basename = f.c_basename
1078 else:
1079 fields = full_name.split(".")
1080 if fields[-1] == '__new__':
1081 fields.pop()
1082 c_basename = "_".join(fields)
Larry Hastings5c661892014-01-24 06:17:25 -08001083
Larry Hastings31826802013-10-19 00:09:25 -07001084 template_dict['c_basename'] = c_basename
1085
1086 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
1087 template_dict['methoddef_name'] = methoddef_name
1088
1089 template_dict['docstring'] = self.docstring_for_c_string(f)
1090
Larry Hastingsc2047262014-01-25 20:43:29 -08001091 template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
Larry Hastings5c661892014-01-24 06:17:25 -08001092 f_self.converter.set_template_dict(template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001093
Larry Hastings31826802013-10-19 00:09:25 -07001094 f.return_converter.render(f, data)
1095 template_dict['impl_return_type'] = f.return_converter.type
1096
1097 template_dict['declarations'] = "\n".join(data.declarations)
1098 template_dict['initializers'] = "\n\n".join(data.initializers)
Larry Hastingsc2047262014-01-25 20:43:29 -08001099 template_dict['modifications'] = '\n\n'.join(data.modifications)
Larry Hastings31826802013-10-19 00:09:25 -07001100 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
1101 template_dict['format_units'] = ''.join(data.format_units)
1102 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
1103 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
1104 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
1105 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
1106 template_dict['cleanup'] = "".join(data.cleanup)
1107 template_dict['return_value'] = data.return_value
1108
Larry Hastings5c661892014-01-24 06:17:25 -08001109 # used by unpack tuple code generator
1110 ignore_self = -1 if isinstance(converters[0], self_converter) else 0
1111 unpack_min = first_optional
1112 unpack_max = len(selfless)
1113 template_dict['unpack_min'] = str(unpack_min)
1114 template_dict['unpack_max'] = str(unpack_max)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08001115
Larry Hastingsbebf7352014-01-17 17:47:17 -08001116 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -07001117 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001118
Larry Hastingsbebf7352014-01-17 17:47:17 -08001119 for name, destination in clinic.field_destinations.items():
1120 template = templates[name]
1121 if has_option_groups:
1122 template = linear_format(template,
1123 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -07001124 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -08001125 declarations=template_dict['declarations'],
1126 return_conversion=template_dict['return_conversion'],
1127 initializers=template_dict['initializers'],
Larry Hastingsc2047262014-01-25 20:43:29 -08001128 modifications=template_dict['modifications'],
Larry Hastingsbebf7352014-01-17 17:47:17 -08001129 cleanup=template_dict['cleanup'],
1130 )
Larry Hastings31826802013-10-19 00:09:25 -07001131
Larry Hastingsbebf7352014-01-17 17:47:17 -08001132 # Only generate the "exit:" label
1133 # if we have any gotos
1134 need_exit_label = "goto exit;" in template
1135 template = linear_format(template,
1136 exit_label="exit:" if need_exit_label else ''
1137 )
Larry Hastings31826802013-10-19 00:09:25 -07001138
Larry Hastingsbebf7352014-01-17 17:47:17 -08001139 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -07001140
Larry Hastingsbebf7352014-01-17 17:47:17 -08001141 if clinic.line_prefix:
1142 s = indent_all_lines(s, clinic.line_prefix)
1143 if clinic.line_suffix:
1144 s = suffix_all_lines(s, clinic.line_suffix)
1145
1146 destination.append(s)
1147
1148 return clinic.get_destination('block').dump()
1149
Larry Hastings31826802013-10-19 00:09:25 -07001150
1151
Larry Hastings5c661892014-01-24 06:17:25 -08001152
Larry Hastings31826802013-10-19 00:09:25 -07001153@contextlib.contextmanager
1154def OverrideStdioWith(stdout):
1155 saved_stdout = sys.stdout
1156 sys.stdout = stdout
1157 try:
1158 yield
1159 finally:
1160 assert sys.stdout is stdout
1161 sys.stdout = saved_stdout
1162
1163
Larry Hastings581ee362014-01-28 05:00:08 -08001164def create_regex(before, after, word=True):
Larry Hastings31826802013-10-19 00:09:25 -07001165 """Create an re object for matching marker lines."""
Larry Hastings581ee362014-01-28 05:00:08 -08001166 group_re = "\w+" if word else ".+"
1167 pattern = r'^{}({}){}$'
1168 pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1169 return re.compile(pattern)
Larry Hastings31826802013-10-19 00:09:25 -07001170
1171
1172class Block:
1173 r"""
1174 Represents a single block of text embedded in
1175 another file. If dsl_name is None, the block represents
1176 verbatim text, raw original text from the file, in
1177 which case "input" will be the only non-false member.
1178 If dsl_name is not None, the block represents a Clinic
1179 block.
1180
1181 input is always str, with embedded \n characters.
1182 input represents the original text from the file;
1183 if it's a Clinic block, it is the original text with
1184 the body_prefix and redundant leading whitespace removed.
1185
1186 dsl_name is either str or None. If str, it's the text
1187 found on the start line of the block between the square
1188 brackets.
1189
1190 signatures is either list or None. If it's a list,
1191 it may only contain clinic.Module, clinic.Class, and
1192 clinic.Function objects. At the moment it should
1193 contain at most one of each.
1194
1195 output is either str or None. If str, it's the output
1196 from this block, with embedded '\n' characters.
1197
1198 indent is either str or None. It's the leading whitespace
1199 that was found on every line of input. (If body_prefix is
1200 not empty, this is the indent *after* removing the
1201 body_prefix.)
1202
1203 preindent is either str or None. It's the whitespace that
1204 was found in front of every line of input *before* the
1205 "body_prefix" (see the Language object). If body_prefix
1206 is empty, preindent must always be empty too.
1207
1208 To illustrate indent and preindent: Assume that '_'
1209 represents whitespace. If the block processed was in a
1210 Python file, and looked like this:
1211 ____#/*[python]
1212 ____#__for a in range(20):
1213 ____#____print(a)
1214 ____#[python]*/
1215 "preindent" would be "____" and "indent" would be "__".
1216
1217 """
1218 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1219 assert isinstance(input, str)
1220 self.input = input
1221 self.dsl_name = dsl_name
1222 self.signatures = signatures or []
1223 self.output = output
1224 self.indent = indent
1225 self.preindent = preindent
1226
Larry Hastings581ee362014-01-28 05:00:08 -08001227 def __repr__(self):
1228 dsl_name = self.dsl_name or "text"
1229 def summarize(s):
1230 s = repr(s)
1231 if len(s) > 30:
1232 return s[:26] + "..." + s[0]
1233 return s
1234 return "".join((
1235 "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
1236
Larry Hastings31826802013-10-19 00:09:25 -07001237
1238class BlockParser:
1239 """
1240 Block-oriented parser for Argument Clinic.
1241 Iterator, yields Block objects.
1242 """
1243
1244 def __init__(self, input, language, *, verify=True):
1245 """
1246 "input" should be a str object
1247 with embedded \n characters.
1248
1249 "language" should be a Language object.
1250 """
1251 language.validate()
1252
1253 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1254 self.block_start_line_number = self.line_number = 0
1255
1256 self.language = language
1257 before, _, after = language.start_line.partition('{dsl_name}')
1258 assert _ == '{dsl_name}'
1259 self.start_re = create_regex(before, after)
1260 self.verify = verify
1261 self.last_checksum_re = None
1262 self.last_dsl_name = None
1263 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001264 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001265
1266 def __iter__(self):
1267 return self
1268
1269 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001270 while True:
1271 if not self.input:
1272 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001273
Larry Hastingsbebf7352014-01-17 17:47:17 -08001274 if self.dsl_name:
1275 return_value = self.parse_clinic_block(self.dsl_name)
1276 self.dsl_name = None
1277 self.first_block = False
1278 return return_value
1279 block = self.parse_verbatim_block()
1280 if self.first_block and not block.input:
1281 continue
1282 self.first_block = False
1283 return block
1284
Larry Hastings31826802013-10-19 00:09:25 -07001285
1286 def is_start_line(self, line):
1287 match = self.start_re.match(line.lstrip())
1288 return match.group(1) if match else None
1289
1290 def _line(self):
1291 self.line_number += 1
1292 return self.input.pop()
1293
1294 def parse_verbatim_block(self):
1295 add, output = text_accumulator()
1296 self.block_start_line_number = self.line_number
1297
1298 while self.input:
1299 line = self._line()
1300 dsl_name = self.is_start_line(line)
1301 if dsl_name:
1302 self.dsl_name = dsl_name
1303 break
1304 add(line)
1305
1306 return Block(output())
1307
1308 def parse_clinic_block(self, dsl_name):
1309 input_add, input_output = text_accumulator()
1310 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001311 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001312 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1313
Larry Hastings90261132014-01-07 12:21:08 -08001314 def is_stop_line(line):
1315 # make sure to recognize stop line even if it
1316 # doesn't end with EOL (it could be the very end of the file)
1317 if not line.startswith(stop_line):
1318 return False
1319 remainder = line[len(stop_line):]
1320 return (not remainder) or remainder.isspace()
1321
Larry Hastings31826802013-10-19 00:09:25 -07001322 # consume body of program
1323 while self.input:
1324 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001325 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001326 break
1327 if body_prefix:
1328 line = line.lstrip()
1329 assert line.startswith(body_prefix)
1330 line = line[len(body_prefix):]
1331 input_add(line)
1332
1333 # consume output and checksum line, if present.
1334 if self.last_dsl_name == dsl_name:
1335 checksum_re = self.last_checksum_re
1336 else:
Larry Hastings581ee362014-01-28 05:00:08 -08001337 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
1338 assert _ == '{arguments}'
1339 checksum_re = create_regex(before, after, word=False)
Larry Hastings31826802013-10-19 00:09:25 -07001340 self.last_dsl_name = dsl_name
1341 self.last_checksum_re = checksum_re
1342
1343 # scan forward for checksum line
1344 output_add, output_output = text_accumulator()
Larry Hastings581ee362014-01-28 05:00:08 -08001345 arguments = None
Larry Hastings31826802013-10-19 00:09:25 -07001346 while self.input:
1347 line = self._line()
1348 match = checksum_re.match(line.lstrip())
Larry Hastings581ee362014-01-28 05:00:08 -08001349 arguments = match.group(1) if match else None
1350 if arguments:
Larry Hastings31826802013-10-19 00:09:25 -07001351 break
1352 output_add(line)
1353 if self.is_start_line(line):
1354 break
1355
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001356 output = output_output()
Larry Hastings581ee362014-01-28 05:00:08 -08001357 if arguments:
1358 d = {}
1359 for field in shlex.split(arguments):
1360 name, equals, value = field.partition('=')
1361 if not equals:
1362 fail("Mangled Argument Clinic marker line: {!r}".format(line))
1363 d[name.strip()] = value.strip()
1364
Larry Hastings31826802013-10-19 00:09:25 -07001365 if self.verify:
Larry Hastings581ee362014-01-28 05:00:08 -08001366 if 'input' in d:
1367 checksum = d['output']
1368 input_checksum = d['input']
1369 else:
1370 checksum = d['checksum']
1371 input_checksum = None
1372
1373 computed = compute_checksum(output, len(checksum))
Larry Hastings31826802013-10-19 00:09:25 -07001374 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001375 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1376 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001377 "the end marker,\n"
1378 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001379 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001380 else:
1381 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001382 output_lines = output.splitlines(keepends=True)
1383 self.line_number -= len(output_lines)
1384 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001385 output = None
1386
1387 return Block(input_output(), dsl_name, output=output)
1388
1389
1390class BlockPrinter:
1391
1392 def __init__(self, language, f=None):
1393 self.language = language
1394 self.f = f or io.StringIO()
1395
1396 def print_block(self, block):
1397 input = block.input
1398 output = block.output
1399 dsl_name = block.dsl_name
1400 write = self.f.write
1401
Larry Hastings31826802013-10-19 00:09:25 -07001402 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1403
1404 if not dsl_name:
1405 write(input)
1406 return
1407
1408 write(self.language.start_line.format(dsl_name=dsl_name))
1409 write("\n")
1410
1411 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1412 if not body_prefix:
1413 write(input)
1414 else:
1415 for line in input.split('\n'):
1416 write(body_prefix)
1417 write(line)
1418 write("\n")
1419
1420 write(self.language.stop_line.format(dsl_name=dsl_name))
1421 write("\n")
1422
Larry Hastings581ee362014-01-28 05:00:08 -08001423 input = ''.join(block.input)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001424 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001425 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001426 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001427 output += '\n'
1428 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001429
Larry Hastings581ee362014-01-28 05:00:08 -08001430 arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16))
1431 write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
Larry Hastings31826802013-10-19 00:09:25 -07001432 write("\n")
1433
Larry Hastingsbebf7352014-01-17 17:47:17 -08001434 def write(self, text):
1435 self.f.write(text)
1436
1437
1438class Destination:
1439 def __init__(self, name, type, clinic, *args):
1440 self.name = name
1441 self.type = type
1442 self.clinic = clinic
1443 valid_types = ('buffer', 'file', 'suppress', 'two-pass')
1444 if type not in valid_types:
1445 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1446 extra_arguments = 1 if type == "file" else 0
1447 if len(args) < extra_arguments:
1448 fail("Not enough arguments for destination " + name + " new " + type)
1449 if len(args) > extra_arguments:
1450 fail("Too many arguments for destination " + name + " new " + type)
1451 if type =='file':
1452 d = {}
Larry Hastingsc2047262014-01-25 20:43:29 -08001453 filename = clinic.filename
1454 d['path'] = filename
1455 dirname, basename = os.path.split(filename)
1456 if not dirname:
1457 dirname = '.'
1458 d['dirname'] = dirname
1459 d['basename'] = basename
1460 d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001461 self.filename = args[0].format_map(d)
1462 if type == 'two-pass':
1463 self.id = None
1464
1465 self.text, self.append, self._dump = _text_accumulator()
1466
1467 def __repr__(self):
1468 if self.type == 'file':
1469 file_repr = " " + repr(self.filename)
1470 else:
1471 file_repr = ''
1472 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1473
1474 def clear(self):
1475 if self.type != 'buffer':
1476 fail("Can't clear destination" + self.name + " , it's not of type buffer")
1477 self.text.clear()
1478
1479 def dump(self):
1480 if self.type == 'two-pass':
1481 if self.id is None:
1482 self.id = str(uuid.uuid4())
1483 return self.id
1484 fail("You can only dump a two-pass buffer exactly once!")
1485 return self._dump()
1486
Larry Hastings31826802013-10-19 00:09:25 -07001487
1488# maps strings to Language objects.
1489# "languages" maps the name of the language ("C", "Python").
1490# "extensions" maps the file extension ("c", "py").
1491languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001492extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1493extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001494
1495
1496# maps strings to callables.
1497# these callables must be of the form:
1498# def foo(name, default, *, ...)
1499# The callable may have any number of keyword-only parameters.
1500# The callable must return a CConverter object.
1501# The callable should not call builtins.print.
1502converters = {}
1503
1504# maps strings to callables.
1505# these callables follow the same rules as those for "converters" above.
1506# note however that they will never be called with keyword-only parameters.
1507legacy_converters = {}
1508
1509
1510# maps strings to callables.
1511# these callables must be of the form:
1512# def foo(*, ...)
1513# The callable may have any number of keyword-only parameters.
1514# The callable must return a CConverter object.
1515# The callable should not call builtins.print.
1516return_converters = {}
1517
1518class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001519
1520 presets_text = """
1521preset original
1522everything block
1523docstring_prototype suppress
1524parser_prototype suppress
1525
1526preset file
1527everything file
1528docstring_prototype suppress
1529parser_prototype suppress
1530impl_definition block
1531
1532preset buffer
1533everything buffer
1534docstring_prototype suppress
1535impl_prototype suppress
1536parser_prototype suppress
1537impl_definition block
1538
1539preset partial-buffer
1540everything buffer
1541docstring_prototype block
1542impl_prototype suppress
1543methoddef_define block
1544parser_prototype block
1545impl_definition block
1546
1547preset two-pass
1548everything buffer
1549docstring_prototype two-pass
1550impl_prototype suppress
1551methoddef_define two-pass
1552parser_prototype two-pass
1553impl_definition block
1554
1555"""
1556
Larry Hastings581ee362014-01-28 05:00:08 -08001557 def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
Larry Hastings31826802013-10-19 00:09:25 -07001558 # maps strings to Parser objects.
1559 # (instantiated from the "parsers" global.)
1560 self.parsers = {}
1561 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001562 if printer:
1563 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001564 self.printer = printer or BlockPrinter(language)
1565 self.verify = verify
Larry Hastings581ee362014-01-28 05:00:08 -08001566 self.force = force
Larry Hastings31826802013-10-19 00:09:25 -07001567 self.filename = filename
1568 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001569 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001570 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001571
Larry Hastingsbebf7352014-01-17 17:47:17 -08001572 self.line_prefix = self.line_suffix = ''
1573
1574 self.destinations = {}
1575 self.add_destination("block", "buffer")
1576 self.add_destination("suppress", "suppress")
1577 self.add_destination("buffer", "buffer")
1578 self.add_destination("two-pass", "two-pass")
1579 if filename:
Larry Hastingsc2047262014-01-25 20:43:29 -08001580 self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001581
1582 d = self.destinations.get
1583 self.field_destinations = collections.OrderedDict((
1584 ('docstring_prototype', d('suppress')),
1585 ('docstring_definition', d('block')),
1586 ('methoddef_define', d('block')),
1587 ('impl_prototype', d('block')),
1588 ('parser_prototype', d('suppress')),
1589 ('parser_definition', d('block')),
1590 ('impl_definition', d('block')),
1591 ))
1592
1593 self.field_destinations_stack = []
1594
1595 self.presets = {}
1596 preset = None
1597 for line in self.presets_text.strip().split('\n'):
1598 line = line.strip()
1599 if not line:
1600 continue
1601 name, value = line.split()
1602 if name == 'preset':
1603 self.presets[value] = preset = collections.OrderedDict()
1604 continue
1605
1606 destination = self.get_destination(value)
1607
1608 if name == 'everything':
1609 for name in self.field_destinations:
1610 preset[name] = destination
1611 continue
1612
1613 assert name in self.field_destinations
1614 preset[name] = destination
1615
Larry Hastings31826802013-10-19 00:09:25 -07001616 global clinic
1617 clinic = self
1618
Larry Hastingsbebf7352014-01-17 17:47:17 -08001619 def get_destination(self, name, default=unspecified):
1620 d = self.destinations.get(name)
1621 if not d:
1622 if default is not unspecified:
1623 return default
1624 fail("Destination does not exist: " + repr(name))
1625 return d
1626
1627 def add_destination(self, name, type, *args):
1628 if name in self.destinations:
1629 fail("Destination already exists: " + repr(name))
1630 self.destinations[name] = Destination(name, type, self, *args)
1631
Larry Hastings31826802013-10-19 00:09:25 -07001632 def parse(self, input):
1633 printer = self.printer
1634 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1635 for block in self.block_parser:
1636 dsl_name = block.dsl_name
1637 if dsl_name:
1638 if dsl_name not in self.parsers:
1639 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1640 self.parsers[dsl_name] = parsers[dsl_name](self)
1641 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001642 try:
1643 parser.parse(block)
1644 except Exception:
1645 fail('Exception raised during parsing:\n' +
1646 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001647 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001648
1649 second_pass_replacements = {}
1650
1651 for name, destination in self.destinations.items():
1652 if destination.type == 'suppress':
1653 continue
1654 output = destination._dump()
1655
1656 if destination.type == 'two-pass':
1657 if destination.id:
1658 second_pass_replacements[destination.id] = output
1659 elif output:
1660 fail("Two-pass buffer " + repr(name) + " not empty at end of file!")
1661 continue
1662
1663 if output:
1664
1665 block = Block("", dsl_name="clinic", output=output)
1666
1667 if destination.type == 'buffer':
1668 block.input = "dump " + name + "\n"
1669 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1670 printer.write("\n")
1671 printer.print_block(block)
1672 continue
1673
1674 if destination.type == 'file':
1675 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08001676 dirname = os.path.dirname(destination.filename)
1677 try:
1678 os.makedirs(dirname)
1679 except FileExistsError:
1680 if not os.path.isdir(dirname):
1681 fail("Can't write to destination {}, "
1682 "can't make directory {}!".format(
1683 destination.filename, dirname))
Larry Hastings581ee362014-01-28 05:00:08 -08001684 if self.verify:
1685 with open(destination.filename, "rt") as f:
1686 parser_2 = BlockParser(f.read(), language=self.language)
1687 blocks = list(parser_2)
1688 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1689 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
Larry Hastingsbebf7352014-01-17 17:47:17 -08001690 except FileNotFoundError:
1691 pass
1692
1693 block.input = 'preserve\n'
1694 printer_2 = BlockPrinter(self.language)
1695 printer_2.print_block(block)
1696 with open(destination.filename, "wt") as f:
1697 f.write(printer_2.f.getvalue())
1698 continue
1699 text = printer.f.getvalue()
1700
1701 if second_pass_replacements:
1702 printer_2 = BlockPrinter(self.language)
1703 parser_2 = BlockParser(text, self.language)
1704 changed = False
1705 for block in parser_2:
1706 if block.dsl_name:
1707 for id, replacement in second_pass_replacements.items():
1708 if id in block.output:
1709 changed = True
1710 block.output = block.output.replace(id, replacement)
1711 printer_2.print_block(block)
1712 if changed:
1713 text = printer_2.f.getvalue()
1714
1715 return text
1716
Larry Hastings31826802013-10-19 00:09:25 -07001717
1718 def _module_and_class(self, fields):
1719 """
1720 fields should be an iterable of field names.
1721 returns a tuple of (module, class).
1722 the module object could actually be self (a clinic object).
1723 this function is only ever used to find the parent of where
1724 a new class/module should go.
1725 """
1726 in_classes = False
1727 parent = module = self
1728 cls = None
1729 so_far = []
1730
1731 for field in fields:
1732 so_far.append(field)
1733 if not in_classes:
1734 child = parent.modules.get(field)
1735 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001736 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001737 continue
1738 in_classes = True
1739 if not hasattr(parent, 'classes'):
1740 return module, cls
1741 child = parent.classes.get(field)
1742 if not child:
1743 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1744 cls = parent = child
1745
1746 return module, cls
1747
1748
Larry Hastings581ee362014-01-28 05:00:08 -08001749def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
Larry Hastings31826802013-10-19 00:09:25 -07001750 extension = os.path.splitext(filename)[1][1:]
1751 if not extension:
1752 fail("Can't extract file type for file " + repr(filename))
1753
1754 try:
1755 language = extensions[extension]()
1756 except KeyError:
1757 fail("Can't identify file type for file " + repr(filename))
1758
Larry Hastings581ee362014-01-28 05:00:08 -08001759 clinic = Clinic(language, force=force, verify=verify, filename=filename)
Larry Hastings31826802013-10-19 00:09:25 -07001760
1761 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001762 raw = f.read()
1763
1764 cooked = clinic.parse(raw)
Larry Hastings581ee362014-01-28 05:00:08 -08001765 if (cooked == raw) and not force:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001766 return
Larry Hastings31826802013-10-19 00:09:25 -07001767
1768 directory = os.path.dirname(filename) or '.'
1769
1770 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001771 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001772 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1773 with open(tmpfilename, "wb") as f:
1774 f.write(bytes)
1775 os.replace(tmpfilename, output or filename)
1776
1777
Larry Hastings581ee362014-01-28 05:00:08 -08001778def compute_checksum(input, length=None):
Larry Hastings31826802013-10-19 00:09:25 -07001779 input = input or ''
Larry Hastings581ee362014-01-28 05:00:08 -08001780 s = hashlib.sha1(input.encode('utf-8')).hexdigest()
1781 if length:
1782 s = s[:length]
1783 return s
Larry Hastings31826802013-10-19 00:09:25 -07001784
1785
1786
1787
1788class PythonParser:
1789 def __init__(self, clinic):
1790 pass
1791
1792 def parse(self, block):
1793 s = io.StringIO()
1794 with OverrideStdioWith(s):
1795 exec(block.input)
1796 block.output = s.getvalue()
1797
1798
1799class Module:
1800 def __init__(self, name, module=None):
1801 self.name = name
1802 self.module = self.parent = module
1803
1804 self.modules = collections.OrderedDict()
1805 self.classes = collections.OrderedDict()
1806 self.functions = []
1807
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001808 def __repr__(self):
1809 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1810
Larry Hastings31826802013-10-19 00:09:25 -07001811class Class:
Larry Hastingsc2047262014-01-25 20:43:29 -08001812 def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
Larry Hastings31826802013-10-19 00:09:25 -07001813 self.name = name
1814 self.module = module
1815 self.cls = cls
Larry Hastingsc2047262014-01-25 20:43:29 -08001816 self.typedef = typedef
1817 self.type_object = type_object
Larry Hastings31826802013-10-19 00:09:25 -07001818 self.parent = cls or module
1819
1820 self.classes = collections.OrderedDict()
1821 self.functions = []
1822
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001823 def __repr__(self):
1824 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1825
Larry Hastings8666e652014-01-12 14:12:59 -08001826unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001827
Larry Hastings8666e652014-01-12 14:12:59 -08001828__abs__
1829__add__
1830__and__
1831__bytes__
1832__call__
1833__complex__
1834__delitem__
1835__divmod__
1836__eq__
1837__float__
1838__floordiv__
1839__ge__
1840__getattr__
1841__getattribute__
1842__getitem__
1843__gt__
1844__hash__
1845__iadd__
1846__iand__
1847__idivmod__
1848__ifloordiv__
1849__ilshift__
1850__imod__
1851__imul__
1852__index__
1853__int__
1854__invert__
1855__ior__
1856__ipow__
1857__irshift__
1858__isub__
1859__iter__
1860__itruediv__
1861__ixor__
1862__le__
1863__len__
1864__lshift__
1865__lt__
1866__mod__
1867__mul__
1868__neg__
1869__new__
1870__next__
1871__or__
1872__pos__
1873__pow__
1874__radd__
1875__rand__
1876__rdivmod__
1877__repr__
1878__rfloordiv__
1879__rlshift__
1880__rmod__
1881__rmul__
1882__ror__
1883__round__
1884__rpow__
1885__rrshift__
1886__rshift__
1887__rsub__
1888__rtruediv__
1889__rxor__
1890__setattr__
1891__setitem__
1892__str__
1893__sub__
1894__truediv__
1895__xor__
1896
1897""".strip().split())
1898
1899
Larry Hastings5c661892014-01-24 06:17:25 -08001900INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """
1901INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
1902""".replace(",", "").strip().split()
Larry Hastings31826802013-10-19 00:09:25 -07001903
1904class Function:
1905 """
1906 Mutable duck type for inspect.Function.
1907
1908 docstring - a str containing
1909 * embedded line breaks
1910 * text outdented to the left margin
1911 * no trailing whitespace.
1912 It will always be true that
1913 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1914 """
1915
1916 def __init__(self, parameters=None, *, name,
1917 module, cls=None, c_basename=None,
1918 full_name=None,
1919 return_converter, return_annotation=_empty,
Larry Hastings581ee362014-01-28 05:00:08 -08001920 docstring=None, kind=CALLABLE, coexist=False,
1921 suppress_signature=False):
Larry Hastings31826802013-10-19 00:09:25 -07001922 self.parameters = parameters or collections.OrderedDict()
1923 self.return_annotation = return_annotation
1924 self.name = name
1925 self.full_name = full_name
1926 self.module = module
1927 self.cls = cls
1928 self.parent = cls or module
1929 self.c_basename = c_basename
1930 self.return_converter = return_converter
1931 self.docstring = docstring or ''
1932 self.kind = kind
1933 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001934 self.self_converter = None
Larry Hastings581ee362014-01-28 05:00:08 -08001935 self.suppress_signature = suppress_signature
Larry Hastingsebdcb502013-11-23 14:54:00 -08001936
1937 @property
1938 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001939 if self.kind in (METHOD_INIT, METHOD_NEW):
1940 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001941 flags = []
1942 if self.kind == CLASS_METHOD:
1943 flags.append('METH_CLASS')
1944 elif self.kind == STATIC_METHOD:
1945 flags.append('METH_STATIC')
1946 else:
1947 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1948 if self.coexist:
1949 flags.append('METH_COEXIST')
1950 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001951
1952 def __repr__(self):
1953 return '<clinic.Function ' + self.name + '>'
1954
1955
1956class Parameter:
1957 """
1958 Mutable duck type of inspect.Parameter.
1959 """
1960
1961 def __init__(self, name, kind, *, default=_empty,
1962 function, converter, annotation=_empty,
1963 docstring=None, group=0):
1964 self.name = name
1965 self.kind = kind
1966 self.default = default
1967 self.function = function
1968 self.converter = converter
1969 self.annotation = annotation
1970 self.docstring = docstring or ''
1971 self.group = group
1972
1973 def __repr__(self):
1974 return '<clinic.Parameter ' + self.name + '>'
1975
1976 def is_keyword_only(self):
1977 return self.kind == inspect.Parameter.KEYWORD_ONLY
1978
Larry Hastings31826802013-10-19 00:09:25 -07001979
Larry Hastings31826802013-10-19 00:09:25 -07001980
1981def add_c_converter(f, name=None):
1982 if not name:
1983 name = f.__name__
1984 if not name.endswith('_converter'):
1985 return f
1986 name = name[:-len('_converter')]
1987 converters[name] = f
1988 return f
1989
1990def add_default_legacy_c_converter(cls):
1991 # automatically add converter for default format unit
1992 # (but without stomping on the existing one if it's already
1993 # set, in case you subclass)
1994 if ((cls.format_unit != 'O&') and
1995 (cls.format_unit not in legacy_converters)):
1996 legacy_converters[cls.format_unit] = cls
1997 return cls
1998
1999def add_legacy_c_converter(format_unit, **kwargs):
2000 """
2001 Adds a legacy converter.
2002 """
2003 def closure(f):
2004 if not kwargs:
2005 added_f = f
2006 else:
2007 added_f = functools.partial(f, **kwargs)
2008 legacy_converters[format_unit] = added_f
2009 return f
2010 return closure
2011
2012class CConverterAutoRegister(type):
2013 def __init__(cls, name, bases, classdict):
2014 add_c_converter(cls)
2015 add_default_legacy_c_converter(cls)
2016
2017class CConverter(metaclass=CConverterAutoRegister):
2018 """
2019 For the init function, self, name, function, and default
2020 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08002021 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07002022 """
2023
Larry Hastings78cf85c2014-01-04 12:44:57 -08002024 # The C type to use for this variable.
2025 # 'type' should be a Python string specifying the type, e.g. "int".
2026 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002027 type = None
Larry Hastings31826802013-10-19 00:09:25 -07002028
2029 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08002030 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08002031 # Or the magic value "unknown" if this value is a cannot be evaluated
2032 # at Argument-Clinic-preprocessing time (but is presumed to be valid
2033 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07002034 default = unspecified
2035
Larry Hastings4a55fc52014-01-12 11:09:57 -08002036 # If not None, default must be isinstance() of this type.
2037 # (You can also specify a tuple of types.)
2038 default_type = None
2039
Larry Hastings31826802013-10-19 00:09:25 -07002040 # "default" converted into a C value, as a string.
2041 # Or None if there is no default.
2042 c_default = None
2043
Larry Hastings2a727912014-01-16 11:32:01 -08002044 # "default" converted into a Python value, as a string.
2045 # Or None if there is no default.
2046 py_default = None
2047
Larry Hastingsabc716b2013-11-20 09:13:52 -08002048 # The default value used to initialize the C variable when
2049 # there is no default, but not specifying a default may
2050 # result in an "uninitialized variable" warning. This can
2051 # easily happen when using option groups--although
2052 # properly-written code won't actually use the variable,
2053 # the variable does get passed in to the _impl. (Ah, if
2054 # only dataflow analysis could inline the static function!)
2055 #
2056 # This value is specified as a string.
2057 # Every non-abstract subclass should supply a valid value.
2058 c_ignored_default = 'NULL'
2059
Larry Hastings31826802013-10-19 00:09:25 -07002060 # The C converter *function* to be used, if any.
2061 # (If this is not None, format_unit must be 'O&'.)
2062 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08002063
Larry Hastings78cf85c2014-01-04 12:44:57 -08002064 # Should Argument Clinic add a '&' before the name of
2065 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07002066 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08002067
2068 # Should Argument Clinic add a '&' before the name of
2069 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07002070 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08002071
2072 #############################################################
2073 #############################################################
2074 ## You shouldn't need to read anything below this point to ##
2075 ## write your own converter functions. ##
2076 #############################################################
2077 #############################################################
2078
2079 # The "format unit" to specify for this variable when
2080 # parsing arguments using PyArg_ParseTuple (AndKeywords).
2081 # Custom converters should always use the default value of 'O&'.
2082 format_unit = 'O&'
2083
2084 # What encoding do we want for this variable? Only used
2085 # by format units starting with 'e'.
2086 encoding = None
2087
Larry Hastings77561cc2014-01-07 12:13:13 -08002088 # Should this object be required to be a subclass of a specific type?
2089 # If not None, should be a string representing a pointer to a
2090 # PyTypeObject (e.g. "&PyUnicode_Type").
2091 # Only used by the 'O!' format unit (and the "object" converter).
2092 subclass_of = None
2093
Larry Hastings78cf85c2014-01-04 12:44:57 -08002094 # Do we want an adjacent '_length' variable for this variable?
2095 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07002096 length = False
2097
Larry Hastings5c661892014-01-24 06:17:25 -08002098 # Should we show this parameter in the generated
2099 # __text_signature__? This is *almost* always True.
Larry Hastingsc2047262014-01-25 20:43:29 -08002100 # (It's only False for __new__, __init__, and METH_STATIC functions.)
Larry Hastings5c661892014-01-24 06:17:25 -08002101 show_in_signature = True
2102
2103 # Overrides the name used in a text signature.
2104 # The name used for a "self" parameter must be one of
2105 # self, type, or module; however users can set their own.
2106 # This lets the self_converter overrule the user-settable
2107 # name, *just* for the text signature.
2108 # Only set by self_converter.
2109 signature_name = None
2110
2111 # keep in sync with self_converter.__init__!
Larry Hastings2a727912014-01-16 11:32:01 -08002112 def __init__(self, name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Larry Hastings31826802013-10-19 00:09:25 -07002113 self.function = function
2114 self.name = name
2115
2116 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08002117 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002118 if isinstance(self.default_type, type):
2119 types_str = self.default_type.__name__
2120 else:
2121 types_str = ', '.join((cls.__name__ for cls in self.default_type))
2122 fail("{}: default value {!r} for field {} is not of type {}".format(
2123 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07002124 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08002125
Larry Hastingsb4705752014-01-18 21:54:15 -08002126 if c_default:
2127 self.c_default = c_default
2128 if py_default:
2129 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08002130
Larry Hastings31826802013-10-19 00:09:25 -07002131 if annotation != unspecified:
2132 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings31826802013-10-19 00:09:25 -07002133 self.converter_init(**kwargs)
2134
2135 def converter_init(self):
2136 pass
2137
2138 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002139 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07002140
Larry Hastings5c661892014-01-24 06:17:25 -08002141 def _render_self(self, parameter, data):
2142 self.parameter = parameter
2143 original_name = self.name
2144 name = ensure_legal_c_identifier(original_name)
2145
2146 # impl_arguments
2147 s = ("&" if self.impl_by_reference else "") + name
2148 data.impl_arguments.append(s)
2149 if self.length:
2150 data.impl_arguments.append(self.length_name())
2151
2152 # impl_parameters
2153 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
2154 if self.length:
2155 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
2156
2157 def _render_non_self(self, parameter, data):
Larry Hastingsabc716b2013-11-20 09:13:52 -08002158 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08002159 original_name = self.name
2160 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002161
2162 # declarations
2163 d = self.declaration()
2164 data.declarations.append(d)
2165
2166 # initializers
2167 initializers = self.initialize()
2168 if initializers:
2169 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
2170
Larry Hastingsc2047262014-01-25 20:43:29 -08002171 # modifications
2172 modifications = self.modify()
2173 if modifications:
2174 data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
2175
Larry Hastings31826802013-10-19 00:09:25 -07002176 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08002177 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07002178
2179 # format_units
2180 if self.is_optional() and '|' not in data.format_units:
2181 data.format_units.append('|')
2182 if parameter.is_keyword_only() and '$' not in data.format_units:
2183 data.format_units.append('$')
2184 data.format_units.append(self.format_unit)
2185
2186 # parse_arguments
2187 self.parse_argument(data.parse_arguments)
2188
Larry Hastings31826802013-10-19 00:09:25 -07002189 # cleanup
2190 cleanup = self.cleanup()
2191 if cleanup:
2192 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
2193
Larry Hastings5c661892014-01-24 06:17:25 -08002194 def render(self, parameter, data):
2195 """
2196 parameter is a clinic.Parameter instance.
2197 data is a CRenderData instance.
2198 """
2199 self._render_self(parameter, data)
2200 self._render_non_self(parameter, data)
2201
Larry Hastingsebdcb502013-11-23 14:54:00 -08002202 def length_name(self):
2203 """Computes the name of the associated "length" variable."""
2204 if not self.length:
2205 return None
2206 return ensure_legal_c_identifier(self.name) + "_length"
2207
Larry Hastings31826802013-10-19 00:09:25 -07002208 # Why is this one broken out separately?
2209 # For "positional-only" function parsing,
2210 # which generates a bunch of PyArg_ParseTuple calls.
2211 def parse_argument(self, list):
2212 assert not (self.converter and self.encoding)
2213 if self.format_unit == 'O&':
2214 assert self.converter
2215 list.append(self.converter)
2216
2217 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08002218 list.append(c_repr(self.encoding))
2219 elif self.subclass_of:
2220 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07002221
Larry Hastingsebdcb502013-11-23 14:54:00 -08002222 legal_name = ensure_legal_c_identifier(self.name)
2223 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07002224 list.append(s)
2225
Larry Hastingsebdcb502013-11-23 14:54:00 -08002226 if self.length:
2227 list.append("&" + self.length_name())
2228
Larry Hastings31826802013-10-19 00:09:25 -07002229 #
2230 # All the functions after here are intended as extension points.
2231 #
2232
2233 def simple_declaration(self, by_reference=False):
2234 """
2235 Computes the basic declaration of the variable.
2236 Used in computing the prototype declaration and the
2237 variable declaration.
2238 """
2239 prototype = [self.type]
2240 if by_reference or not self.type.endswith('*'):
2241 prototype.append(" ")
2242 if by_reference:
2243 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002244 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002245 return "".join(prototype)
2246
2247 def declaration(self):
2248 """
2249 The C statement to declare this variable.
2250 """
2251 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002252 default = self.c_default
2253 if not default and self.parameter.group:
2254 default = self.c_ignored_default
2255 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002256 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002257 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002258 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002259 if self.length:
2260 declaration.append('\nPy_ssize_clean_t ')
2261 declaration.append(self.length_name())
2262 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08002263 s = "".join(declaration)
2264 # double up curly-braces, this string will be used
2265 # as part of a format_map() template later
2266 s = s.replace("{", "{{")
2267 s = s.replace("}", "}}")
2268 return s
Larry Hastings31826802013-10-19 00:09:25 -07002269
2270 def initialize(self):
2271 """
2272 The C statements required to set up this variable before parsing.
2273 Returns a string containing this code indented at column 0.
2274 If no initialization is necessary, returns an empty string.
2275 """
2276 return ""
2277
Larry Hastingsc2047262014-01-25 20:43:29 -08002278 def modify(self):
2279 """
2280 The C statements required to modify this variable after parsing.
2281 Returns a string containing this code indented at column 0.
2282 If no initialization is necessary, returns an empty string.
2283 """
2284 return ""
2285
Larry Hastings31826802013-10-19 00:09:25 -07002286 def cleanup(self):
2287 """
2288 The C statements required to clean up after this variable.
2289 Returns a string containing this code indented at column 0.
2290 If no cleanup is necessary, returns an empty string.
2291 """
2292 return ""
2293
2294
2295class bool_converter(CConverter):
2296 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002297 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002298 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002299 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002300
2301 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002302 if self.default is not unspecified:
2303 self.default = bool(self.default)
2304 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002305
2306class char_converter(CConverter):
2307 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002308 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07002309 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002310 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002311
Larry Hastings4a55fc52014-01-12 11:09:57 -08002312 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002313 if isinstance(self.default, str) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002314 fail("char_converter: illegal default value " + repr(self.default))
2315
2316
Larry Hastings31826802013-10-19 00:09:25 -07002317@add_legacy_c_converter('B', bitwise=True)
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002318class unsigned_char_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002319 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002320 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002321 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002322 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002323
2324 def converter_init(self, *, bitwise=False):
2325 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002326 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002327
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002328class byte_converter(unsigned_char_converter): pass
2329
Larry Hastings31826802013-10-19 00:09:25 -07002330class short_converter(CConverter):
2331 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002332 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002333 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002334 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002335
2336class unsigned_short_converter(CConverter):
2337 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002338 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002339 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002340 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002341
2342 def converter_init(self, *, bitwise=False):
2343 if not bitwise:
2344 fail("Unsigned shorts must be bitwise (for now).")
2345
Larry Hastingsebdcb502013-11-23 14:54:00 -08002346@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07002347class int_converter(CConverter):
2348 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002349 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002350 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002351 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002352
Larry Hastingsebdcb502013-11-23 14:54:00 -08002353 def converter_init(self, *, types='int'):
2354 if types == 'str':
2355 self.format_unit = 'C'
2356 elif types != 'int':
2357 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07002358
2359class unsigned_int_converter(CConverter):
2360 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002361 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002362 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002363 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002364
2365 def converter_init(self, *, bitwise=False):
2366 if not bitwise:
2367 fail("Unsigned ints must be bitwise (for now).")
2368
2369class long_converter(CConverter):
2370 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002371 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002372 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002373 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002374
2375class unsigned_long_converter(CConverter):
2376 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002377 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002378 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002379 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002380
2381 def converter_init(self, *, bitwise=False):
2382 if not bitwise:
2383 fail("Unsigned longs must be bitwise (for now).")
2384
2385class PY_LONG_LONG_converter(CConverter):
2386 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002387 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002388 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002389 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002390
2391class unsigned_PY_LONG_LONG_converter(CConverter):
2392 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002393 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002394 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002395 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002396
2397 def converter_init(self, *, bitwise=False):
2398 if not bitwise:
2399 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
2400
2401class Py_ssize_t_converter(CConverter):
2402 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002403 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002404 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002405 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002406
2407
2408class float_converter(CConverter):
2409 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002410 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002411 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002412 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002413
2414class double_converter(CConverter):
2415 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002416 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002417 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002418 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002419
2420
2421class Py_complex_converter(CConverter):
2422 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002423 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002424 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002425 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002426
2427
2428class object_converter(CConverter):
2429 type = 'PyObject *'
2430 format_unit = 'O'
2431
Larry Hastings4a55fc52014-01-12 11:09:57 -08002432 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2433 if converter:
2434 if subclass_of:
2435 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2436 self.format_unit = 'O&'
2437 self.converter = converter
2438 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002439 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002440 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002441
Larry Hastings77561cc2014-01-07 12:13:13 -08002442 if type is not None:
2443 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002444
2445
Larry Hastingsebdcb502013-11-23 14:54:00 -08002446@add_legacy_c_converter('s#', length=True)
Larry Hastings2a727912014-01-16 11:32:01 -08002447@add_legacy_c_converter('y', types="bytes")
2448@add_legacy_c_converter('y#', types="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002449@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002450@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002451class str_converter(CConverter):
2452 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002453 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002454 format_unit = 's'
2455
Larry Hastingsebdcb502013-11-23 14:54:00 -08002456 def converter_init(self, *, encoding=None, types="str",
2457 length=False, nullable=False, zeroes=False):
2458
2459 types = set(types.strip().split())
2460 bytes_type = set(("bytes",))
2461 str_type = set(("str",))
2462 all_3_type = set(("bytearray",)) | bytes_type | str_type
2463 is_bytes = types == bytes_type
2464 is_str = types == str_type
2465 is_all_3 = types == all_3_type
2466
2467 self.length = bool(length)
2468 format_unit = None
2469
2470 if encoding:
2471 self.encoding = encoding
2472
2473 if is_str and not (length or zeroes or nullable):
2474 format_unit = 'es'
2475 elif is_all_3 and not (length or zeroes or nullable):
2476 format_unit = 'et'
2477 elif is_str and length and zeroes and not nullable:
2478 format_unit = 'es#'
2479 elif is_all_3 and length and not (nullable or zeroes):
2480 format_unit = 'et#'
2481
2482 if format_unit.endswith('#'):
Larry Hastings5c661892014-01-24 06:17:25 -08002483 fail("Sorry: code using format unit ", repr(format_unit), "probably doesn't work properly yet.\nGive Larry your test case and he'll it.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002484 # TODO set pointer to NULL
2485 # TODO add cleanup for buffer
2486 pass
2487
2488 else:
2489 if zeroes:
2490 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
2491
2492 if is_bytes and not (nullable or length):
2493 format_unit = 'y'
2494 elif is_bytes and length and not nullable:
2495 format_unit = 'y#'
2496 elif is_str and not (nullable or length):
2497 format_unit = 's'
2498 elif is_str and length and not nullable:
2499 format_unit = 's#'
2500 elif is_str and nullable and not length:
2501 format_unit = 'z'
2502 elif is_str and nullable and length:
2503 format_unit = 'z#'
2504
2505 if not format_unit:
2506 fail("str_converter: illegal combination of arguments")
2507 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002508
2509
2510class PyBytesObject_converter(CConverter):
2511 type = 'PyBytesObject *'
2512 format_unit = 'S'
2513
2514class PyByteArrayObject_converter(CConverter):
2515 type = 'PyByteArrayObject *'
2516 format_unit = 'Y'
2517
2518class unicode_converter(CConverter):
2519 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002520 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002521 format_unit = 'U'
2522
Larry Hastingsebdcb502013-11-23 14:54:00 -08002523@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002524@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002525@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002526class Py_UNICODE_converter(CConverter):
2527 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002528 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002529 format_unit = 'u'
2530
Larry Hastingsebdcb502013-11-23 14:54:00 -08002531 def converter_init(self, *, nullable=False, length=False):
2532 format_unit = 'Z' if nullable else 'u'
2533 if length:
2534 format_unit += '#'
2535 self.length = True
2536 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002537
Larry Hastingsebdcb502013-11-23 14:54:00 -08002538#
2539# We define three string conventions for buffer types in the 'types' argument:
2540# 'buffer' : any object supporting the buffer interface
2541# 'rwbuffer': any object supporting the buffer interface, but must be writeable
2542# 'robuffer': any object supporting the buffer interface, but must not be writeable
2543#
2544@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
2545@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
2546@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07002547class Py_buffer_converter(CConverter):
2548 type = 'Py_buffer'
2549 format_unit = 'y*'
2550 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002551 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002552
Larry Hastingsebdcb502013-11-23 14:54:00 -08002553 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002554 if self.default not in (unspecified, None):
2555 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08002556 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002557 types = set(types.strip().split())
2558 bytes_type = set(('bytes',))
2559 bytearray_type = set(('bytearray',))
2560 buffer_type = set(('buffer',))
2561 rwbuffer_type = set(('rwbuffer',))
2562 robuffer_type = set(('robuffer',))
2563 str_type = set(('str',))
2564 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
2565
2566 format_unit = None
2567 if types == (str_type | bytes_bytearray_buffer_type):
2568 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07002569 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002570 if nullable:
2571 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
2572 elif types == (bytes_bytearray_buffer_type):
2573 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002574 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002575 format_unit = 'w*'
2576 if not format_unit:
2577 fail("Py_buffer_converter: illegal combination of arguments")
2578
2579 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002580
2581 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002582 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002583 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002584
2585
Larry Hastings5c661892014-01-24 06:17:25 -08002586def correct_name_for_self(f):
2587 if f.kind in (CALLABLE, METHOD_INIT):
2588 if f.cls:
2589 return "PyObject *", "self"
2590 return "PyModuleDef *", "module"
2591 if f.kind == STATIC_METHOD:
2592 return "void *", "null"
2593 if f.kind in (CLASS_METHOD, METHOD_NEW):
2594 return "PyTypeObject *", "type"
2595 raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
2596
Larry Hastingsc2047262014-01-25 20:43:29 -08002597def required_type_for_self_for_parser(f):
2598 type, _ = correct_name_for_self(f)
2599 if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
2600 return type
2601 return None
2602
Larry Hastings5c661892014-01-24 06:17:25 -08002603
Larry Hastingsebdcb502013-11-23 14:54:00 -08002604class self_converter(CConverter):
2605 """
2606 A special-case converter:
2607 this is the default converter used for "self".
2608 """
Larry Hastings5c661892014-01-24 06:17:25 -08002609 type = None
2610 format_unit = ''
2611
2612
Larry Hastings78cf85c2014-01-04 12:44:57 -08002613 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002614 f = self.function
Larry Hastings5c661892014-01-24 06:17:25 -08002615 default_type, default_name = correct_name_for_self(f)
2616 self.signature_name = default_name
2617 self.type = type or self.type or default_type
Larry Hastingsebdcb502013-11-23 14:54:00 -08002618
Larry Hastings5c661892014-01-24 06:17:25 -08002619 kind = self.function.kind
2620 new_or_init = kind in (METHOD_NEW, METHOD_INIT)
2621
2622 if (kind == STATIC_METHOD) or new_or_init:
2623 self.show_in_signature = False
2624
2625 # tp_new (METHOD_NEW) functions are of type newfunc:
2626 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
2627 # PyTypeObject is a typedef for struct _typeobject.
2628 #
2629 # tp_init (METHOD_INIT) functions are of type initproc:
2630 # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
2631 #
2632 # All other functions generated by Argument Clinic are stored in
2633 # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction:
2634 # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
2635 # However! We habitually cast these functions to PyCFunction,
2636 # since functions that accept keyword arguments don't fit this signature
2637 # but are stored there anyway. So strict type equality isn't important
2638 # for these functions.
2639 #
2640 # So:
2641 #
2642 # * The name of the first parameter to the impl and the parsing function will always
2643 # be self.name.
2644 #
2645 # * The type of the first parameter to the impl will always be of self.type.
2646 #
2647 # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT):
2648 # * The type of the first parameter to the parsing function is also self.type.
2649 # This means that if you step into the parsing function, your "self" parameter
2650 # is of the correct type, which may make debugging more pleasant.
2651 #
2652 # * Else if the function is tp_new (METHOD_NEW):
2653 # * The type of the first parameter to the parsing function is "PyTypeObject *",
2654 # so the type signature of the function call is an exact match.
2655 # * If self.type != "PyTypeObject *", we cast the first parameter to self.type
2656 # in the impl call.
2657 #
2658 # * Else if the function is tp_init (METHOD_INIT):
2659 # * The type of the first parameter to the parsing function is "PyObject *",
2660 # so the type signature of the function call is an exact match.
2661 # * If self.type != "PyObject *", we cast the first parameter to self.type
2662 # in the impl call.
2663
2664 @property
2665 def parser_type(self):
Larry Hastingsc2047262014-01-25 20:43:29 -08002666 return required_type_for_self_for_parser(self.function) or self.type
Larry Hastings78cf85c2014-01-04 12:44:57 -08002667
Larry Hastingsebdcb502013-11-23 14:54:00 -08002668 def render(self, parameter, data):
Larry Hastings5c661892014-01-24 06:17:25 -08002669 """
2670 parameter is a clinic.Parameter instance.
2671 data is a CRenderData instance.
2672 """
2673 if self.function.kind == STATIC_METHOD:
2674 return
2675
2676 self._render_self(parameter, data)
2677
2678 if self.type != self.parser_type:
2679 # insert cast to impl_argument[0], aka self.
2680 # we know we're in the first slot in all the CRenderData lists,
2681 # because we render parameters in order, and self is always first.
2682 assert len(data.impl_arguments) == 1
2683 assert data.impl_arguments[0] == self.name
2684 data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0]
2685
2686 def set_template_dict(self, template_dict):
2687 template_dict['self_name'] = self.name
2688 template_dict['self_type'] = self.parser_type
Larry Hastingsf0537e82014-01-25 22:01:12 -08002689 kind = self.function.kind
2690 cls = self.function.cls
2691
2692 if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef):
2693 if kind == METHOD_NEW:
2694 passed_in_type = self.name
2695 else:
2696 passed_in_type = 'Py_TYPE({})'.format(self.name)
2697
2698 line = '({passed_in_type} == {type_object}) &&\n '
2699 d = {
2700 'type_object': self.function.cls.type_object,
2701 'passed_in_type': passed_in_type
2702 }
2703 template_dict['self_type_check'] = line.format_map(d)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002704
Larry Hastings31826802013-10-19 00:09:25 -07002705
2706
2707def add_c_return_converter(f, name=None):
2708 if not name:
2709 name = f.__name__
2710 if not name.endswith('_return_converter'):
2711 return f
2712 name = name[:-len('_return_converter')]
2713 return_converters[name] = f
2714 return f
2715
2716
2717class CReturnConverterAutoRegister(type):
2718 def __init__(cls, name, bases, classdict):
2719 add_c_return_converter(cls)
2720
2721class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2722
Larry Hastings78cf85c2014-01-04 12:44:57 -08002723 # The C type to use for this variable.
2724 # 'type' should be a Python string specifying the type, e.g. "int".
2725 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002726 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002727
2728 # The Python default value for this parameter, as a Python value.
2729 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002730 default = None
2731
Larry Hastings2a727912014-01-16 11:32:01 -08002732 def __init__(self, *, py_default=None, **kwargs):
2733 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002734 try:
2735 self.return_converter_init(**kwargs)
2736 except TypeError as e:
2737 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2738 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2739
2740 def return_converter_init(self):
2741 pass
2742
2743 def declare(self, data, name="_return_value"):
2744 line = []
2745 add = line.append
2746 add(self.type)
2747 if not self.type.endswith('*'):
2748 add(' ')
2749 add(name + ';')
2750 data.declarations.append(''.join(line))
2751 data.return_value = name
2752
2753 def err_occurred_if(self, expr, data):
2754 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2755
2756 def err_occurred_if_null_pointer(self, variable, data):
2757 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2758
2759 def render(self, function, data):
2760 """
2761 function is a clinic.Function instance.
2762 data is a CRenderData instance.
2763 """
2764 pass
2765
2766add_c_return_converter(CReturnConverter, 'object')
2767
Larry Hastings78cf85c2014-01-04 12:44:57 -08002768class NoneType_return_converter(CReturnConverter):
2769 def render(self, function, data):
2770 self.declare(data)
2771 data.return_conversion.append('''
2772if (_return_value != Py_None)
2773 goto exit;
2774return_value = Py_None;
2775Py_INCREF(Py_None);
2776'''.strip())
2777
Larry Hastings4a55fc52014-01-12 11:09:57 -08002778class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002779 type = 'int'
2780
2781 def render(self, function, data):
2782 self.declare(data)
2783 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002784 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002785
2786class long_return_converter(CReturnConverter):
2787 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002788 conversion_fn = 'PyLong_FromLong'
2789 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002790
2791 def render(self, function, data):
2792 self.declare(data)
2793 self.err_occurred_if("_return_value == -1", data)
2794 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002795 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002796
Larry Hastings4a55fc52014-01-12 11:09:57 -08002797class int_return_converter(long_return_converter):
2798 type = 'int'
2799 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002800
Larry Hastingsb7ccb202014-01-18 23:50:21 -08002801class init_return_converter(long_return_converter):
2802 """
2803 Special return converter for __init__ functions.
2804 """
2805 type = 'int'
2806 cast = '(long)'
2807
2808 def render(self, function, data):
2809 pass
2810
Larry Hastings4a55fc52014-01-12 11:09:57 -08002811class unsigned_long_return_converter(long_return_converter):
2812 type = 'unsigned long'
2813 conversion_fn = 'PyLong_FromUnsignedLong'
2814
2815class unsigned_int_return_converter(unsigned_long_return_converter):
2816 type = 'unsigned int'
2817 cast = '(unsigned long)'
2818
2819class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002820 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002821 conversion_fn = 'PyLong_FromSsize_t'
2822
2823class size_t_return_converter(long_return_converter):
2824 type = 'size_t'
2825 conversion_fn = 'PyLong_FromSize_t'
2826
2827
2828class double_return_converter(CReturnConverter):
2829 type = 'double'
2830 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002831
2832 def render(self, function, data):
2833 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002834 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002835 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002836 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2837
2838class float_return_converter(double_return_converter):
2839 type = 'float'
2840 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002841
2842
2843class DecodeFSDefault_return_converter(CReturnConverter):
2844 type = 'char *'
2845
2846 def render(self, function, data):
2847 self.declare(data)
2848 self.err_occurred_if_null_pointer("_return_value", data)
2849 data.return_conversion.append(
2850 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2851
2852
2853class IndentStack:
2854 def __init__(self):
2855 self.indents = []
2856 self.margin = None
2857
2858 def _ensure(self):
2859 if not self.indents:
2860 fail('IndentStack expected indents, but none are defined.')
2861
2862 def measure(self, line):
2863 """
2864 Returns the length of the line's margin.
2865 """
2866 if '\t' in line:
2867 fail('Tab characters are illegal in the Clinic DSL.')
2868 stripped = line.lstrip()
2869 if not len(stripped):
2870 # we can't tell anything from an empty line
2871 # so just pretend it's indented like our current indent
2872 self._ensure()
2873 return self.indents[-1]
2874 return len(line) - len(stripped)
2875
2876 def infer(self, line):
2877 """
2878 Infer what is now the current margin based on this line.
2879 Returns:
2880 1 if we have indented (or this is the first margin)
2881 0 if the margin has not changed
2882 -N if we have dedented N times
2883 """
2884 indent = self.measure(line)
2885 margin = ' ' * indent
2886 if not self.indents:
2887 self.indents.append(indent)
2888 self.margin = margin
2889 return 1
2890 current = self.indents[-1]
2891 if indent == current:
2892 return 0
2893 if indent > current:
2894 self.indents.append(indent)
2895 self.margin = margin
2896 return 1
2897 # indent < current
2898 if indent not in self.indents:
2899 fail("Illegal outdent.")
2900 outdent_count = 0
2901 while indent != current:
2902 self.indents.pop()
2903 current = self.indents[-1]
2904 outdent_count -= 1
2905 self.margin = margin
2906 return outdent_count
2907
2908 @property
2909 def depth(self):
2910 """
2911 Returns how many margins are currently defined.
2912 """
2913 return len(self.indents)
2914
2915 def indent(self, line):
2916 """
2917 Indents a line by the currently defined margin.
2918 """
2919 return self.margin + line
2920
2921 def dedent(self, line):
2922 """
2923 Dedents a line by the currently defined margin.
2924 (The inverse of 'indent'.)
2925 """
2926 margin = self.margin
2927 indent = self.indents[-1]
2928 if not line.startswith(margin):
2929 fail('Cannot dedent, line does not start with the previous margin:')
2930 return line[indent:]
2931
2932
2933class DSLParser:
2934 def __init__(self, clinic):
2935 self.clinic = clinic
2936
2937 self.directives = {}
2938 for name in dir(self):
2939 # functions that start with directive_ are added to directives
2940 _, s, key = name.partition("directive_")
2941 if s:
2942 self.directives[key] = getattr(self, name)
2943
2944 # functions that start with at_ are too, with an @ in front
2945 _, s, key = name.partition("at_")
2946 if s:
2947 self.directives['@' + key] = getattr(self, name)
2948
2949 self.reset()
2950
2951 def reset(self):
2952 self.function = None
2953 self.state = self.state_dsl_start
2954 self.parameter_indent = None
2955 self.keyword_only = False
2956 self.group = 0
2957 self.parameter_state = self.ps_start
Larry Hastingsc2047262014-01-25 20:43:29 -08002958 self.seen_positional_with_default = False
Larry Hastings31826802013-10-19 00:09:25 -07002959 self.indent = IndentStack()
2960 self.kind = CALLABLE
2961 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08002962 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08002963 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07002964
Larry Hastingsebdcb502013-11-23 14:54:00 -08002965 def directive_version(self, required):
2966 global version
2967 if version_comparitor(version, required) < 0:
2968 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2969
Larry Hastings31826802013-10-19 00:09:25 -07002970 def directive_module(self, name):
2971 fields = name.split('.')
2972 new = fields.pop()
2973 module, cls = self.clinic._module_and_class(fields)
2974 if cls:
2975 fail("Can't nest a module inside a class!")
Larry Hastingsc2047262014-01-25 20:43:29 -08002976
2977 if name in module.classes:
2978 fail("Already defined module " + repr(name) + "!")
2979
Larry Hastings31826802013-10-19 00:09:25 -07002980 m = Module(name, module)
2981 module.modules[name] = m
2982 self.block.signatures.append(m)
2983
Larry Hastingsc2047262014-01-25 20:43:29 -08002984 def directive_class(self, name, typedef, type_object):
Larry Hastings31826802013-10-19 00:09:25 -07002985 fields = name.split('.')
2986 in_classes = False
2987 parent = self
2988 name = fields.pop()
2989 so_far = []
2990 module, cls = self.clinic._module_and_class(fields)
2991
Larry Hastingsc2047262014-01-25 20:43:29 -08002992 parent = cls or module
2993 if name in parent.classes:
2994 fail("Already defined class " + repr(name) + "!")
2995
2996 c = Class(name, module, cls, typedef, type_object)
2997 parent.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002998 self.block.signatures.append(c)
2999
Larry Hastingsbebf7352014-01-17 17:47:17 -08003000 def directive_set(self, name, value):
3001 if name not in ("line_prefix", "line_suffix"):
3002 fail("unknown variable", repr(name))
3003
3004 value = value.format_map({
3005 'block comment start': '/*',
3006 'block comment end': '*/',
3007 })
3008
3009 self.clinic.__dict__[name] = value
3010
3011 def directive_destination(self, name, command, *args):
Zachary Ware071baa62014-01-21 23:07:12 -06003012 if command == 'new':
3013 self.clinic.add_destination(name, *args)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003014 return
3015
Zachary Ware071baa62014-01-21 23:07:12 -06003016 if command == 'clear':
Larry Hastingsbebf7352014-01-17 17:47:17 -08003017 self.clinic.get_destination(name).clear()
3018 fail("unknown destination command", repr(command))
3019
3020
3021 def directive_output(self, field, destination=''):
3022 fd = self.clinic.field_destinations
3023
3024 if field == "preset":
3025 preset = self.clinic.presets.get(destination)
3026 if not preset:
3027 fail("Unknown preset " + repr(destination) + "!")
3028 fd.update(preset)
3029 return
3030
3031 if field == "push":
3032 self.clinic.field_destinations_stack.append(fd.copy())
3033 return
3034
3035 if field == "pop":
3036 if not self.clinic.field_destinations_stack:
3037 fail("Can't 'output pop', stack is empty!")
3038 previous_fd = self.clinic.field_destinations_stack.pop()
3039 fd.update(previous_fd)
3040 return
3041
3042 # secret command for debugging!
3043 if field == "print":
3044 self.block.output.append(pprint.pformat(fd))
3045 self.block.output.append('\n')
3046 return
3047
3048 d = self.clinic.get_destination(destination)
3049
3050 if field == "everything":
3051 for name in list(fd):
3052 fd[name] = d
3053 return
3054
3055 if field not in fd:
3056 fail("Invalid field " + repr(field) + ", must be one of:\n " + ", ".join(valid_fields))
3057 fd[field] = d
3058
3059 def directive_dump(self, name):
3060 self.block.output.append(self.clinic.get_destination(name).dump())
3061
3062 def directive_print(self, *args):
3063 self.block.output.append(' '.join(args))
3064 self.block.output.append('\n')
3065
3066 def directive_preserve(self):
3067 if self.preserve_output:
3068 fail("Can't have preserve twice in one block!")
3069 self.preserve_output = True
3070
Larry Hastings31826802013-10-19 00:09:25 -07003071 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003072 if self.kind is not CALLABLE:
3073 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003074 self.kind = CLASS_METHOD
3075
3076 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003077 if self.kind is not CALLABLE:
3078 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07003079 self.kind = STATIC_METHOD
3080
3081 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08003082 if self.coexist:
3083 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07003084 self.coexist = True
3085
3086 def parse(self, block):
3087 self.reset()
3088 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08003089 self.saved_output = self.block.output
3090 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07003091 block_start = self.clinic.block_parser.line_number
3092 lines = block.input.split('\n')
3093 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
3094 if '\t' in line:
3095 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
3096 self.state(line)
3097
3098 self.next(self.state_terminal)
3099 self.state(None)
3100
Larry Hastingsbebf7352014-01-17 17:47:17 -08003101 block.output.extend(self.clinic.language.render(clinic, block.signatures))
3102
3103 if self.preserve_output:
3104 if block.output:
3105 fail("'preserve' only works for blocks that don't produce any output!")
3106 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07003107
3108 @staticmethod
3109 def ignore_line(line):
3110 # ignore comment-only lines
3111 if line.lstrip().startswith('#'):
3112 return True
3113
3114 # Ignore empty lines too
3115 # (but not in docstring sections!)
3116 if not line.strip():
3117 return True
3118
3119 return False
3120
3121 @staticmethod
3122 def calculate_indent(line):
3123 return len(line) - len(line.strip())
3124
3125 def next(self, state, line=None):
3126 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
3127 self.state = state
3128 if line is not None:
3129 self.state(line)
3130
3131 def state_dsl_start(self, line):
3132 # self.block = self.ClinicOutputBlock(self)
3133 if self.ignore_line(line):
3134 return
3135 self.next(self.state_modulename_name, line)
3136
3137 def state_modulename_name(self, line):
3138 # looking for declaration, which establishes the leftmost column
3139 # line should be
3140 # modulename.fnname [as c_basename] [-> return annotation]
3141 # square brackets denote optional syntax.
3142 #
Larry Hastings4a714d42014-01-14 22:22:41 -08003143 # alternatively:
3144 # modulename.fnname [as c_basename] = modulename.existing_fn_name
3145 # clones the parameters and return converter from that
3146 # function. you can't modify them. you must enter a
3147 # new docstring.
3148 #
Larry Hastings31826802013-10-19 00:09:25 -07003149 # (but we might find a directive first!)
3150 #
3151 # this line is permitted to start with whitespace.
3152 # we'll call this number of spaces F (for "function").
3153
3154 if not line.strip():
3155 return
3156
3157 self.indent.infer(line)
3158
3159 # is it a directive?
3160 fields = shlex.split(line)
3161 directive_name = fields[0]
3162 directive = self.directives.get(directive_name, None)
3163 if directive:
Larry Hastingsbebf7352014-01-17 17:47:17 -08003164 try:
3165 directive(*fields[1:])
3166 except TypeError as e:
3167 fail(str(e))
Larry Hastings31826802013-10-19 00:09:25 -07003168 return
3169
Larry Hastings4a714d42014-01-14 22:22:41 -08003170 # are we cloning?
3171 before, equals, existing = line.rpartition('=')
3172 if equals:
3173 full_name, _, c_basename = before.partition(' as ')
3174 full_name = full_name.strip()
3175 c_basename = c_basename.strip()
3176 existing = existing.strip()
3177 if (is_legal_py_identifier(full_name) and
3178 (not c_basename or is_legal_c_identifier(c_basename)) and
3179 is_legal_py_identifier(existing)):
3180 # we're cloning!
3181 fields = [x.strip() for x in existing.split('.')]
3182 function_name = fields.pop()
3183 module, cls = self.clinic._module_and_class(fields)
3184
3185 for existing_function in (cls or module).functions:
3186 if existing_function.name == function_name:
3187 break
3188 else:
3189 existing_function = None
3190 if not existing_function:
Larry Hastingsc2047262014-01-25 20:43:29 -08003191 print("class", cls, "module", module, "exsiting", existing)
3192 print("cls. functions", cls.functions)
Larry Hastings4a714d42014-01-14 22:22:41 -08003193 fail("Couldn't find existing function " + repr(existing) + "!")
3194
3195 fields = [x.strip() for x in full_name.split('.')]
3196 function_name = fields.pop()
3197 module, cls = self.clinic._module_and_class(fields)
3198
3199 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
3200 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
3201 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3202 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
3203
3204 self.function.parameters = existing_function.parameters.copy()
3205
3206 self.block.signatures.append(self.function)
3207 (cls or module).functions.append(self.function)
3208 self.next(self.state_function_docstring)
3209 return
3210
Larry Hastings31826802013-10-19 00:09:25 -07003211 line, _, returns = line.partition('->')
3212
3213 full_name, _, c_basename = line.partition(' as ')
3214 full_name = full_name.strip()
3215 c_basename = c_basename.strip() or None
3216
Larry Hastingsdfcd4672013-10-27 02:49:39 -07003217 if not is_legal_py_identifier(full_name):
3218 fail("Illegal function name: {}".format(full_name))
3219 if c_basename and not is_legal_c_identifier(c_basename):
3220 fail("Illegal C basename: {}".format(c_basename))
3221
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003222 return_converter = None
3223 if returns:
Larry Hastings31826802013-10-19 00:09:25 -07003224 ast_input = "def x() -> {}: pass".format(returns)
3225 module = None
3226 try:
3227 module = ast.parse(ast_input)
3228 except SyntaxError:
3229 pass
3230 if not module:
3231 fail("Badly-formed annotation for " + full_name + ": " + returns)
3232 try:
3233 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003234 if legacy:
3235 fail("Legacy converter {!r} not allowed as a return converter"
3236 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07003237 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01003238 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07003239 return_converter = return_converters[name](**kwargs)
3240 except ValueError:
3241 fail("Badly-formed annotation for " + full_name + ": " + returns)
3242
3243 fields = [x.strip() for x in full_name.split('.')]
3244 function_name = fields.pop()
3245 module, cls = self.clinic._module_and_class(fields)
3246
Larry Hastings8666e652014-01-12 14:12:59 -08003247 fields = full_name.split('.')
3248 if fields[-1] == '__new__':
3249 if (self.kind != CLASS_METHOD) or (not cls):
3250 fail("__new__ must be a class method!")
3251 self.kind = METHOD_NEW
3252 elif fields[-1] == '__init__':
3253 if (self.kind != CALLABLE) or (not cls):
3254 fail("__init__ must be a normal method, not a class or static method!")
3255 self.kind = METHOD_INIT
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003256 if not return_converter:
3257 return_converter = init_return_converter()
Larry Hastings8666e652014-01-12 14:12:59 -08003258 elif fields[-1] in unsupported_special_methods:
Larry Hastings5c661892014-01-24 06:17:25 -08003259 fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)")
Larry Hastings8666e652014-01-12 14:12:59 -08003260
Larry Hastingsb7ccb202014-01-18 23:50:21 -08003261 if not return_converter:
3262 return_converter = CReturnConverter()
3263
Larry Hastings31826802013-10-19 00:09:25 -07003264 if not module:
3265 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
3266 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
3267 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
3268 self.block.signatures.append(self.function)
Larry Hastings5c661892014-01-24 06:17:25 -08003269
3270 # insert a self converter automatically
Larry Hastingsc2047262014-01-25 20:43:29 -08003271 type, name = correct_name_for_self(self.function)
3272 kwargs = {}
3273 if cls and type == "PyObject *":
3274 kwargs['type'] = cls.typedef
3275 sc = self.function.self_converter = self_converter(name, self.function, **kwargs)
Larry Hastings5c661892014-01-24 06:17:25 -08003276 p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
3277 self.function.parameters[sc.name] = p_self
3278
Larry Hastings4a714d42014-01-14 22:22:41 -08003279 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07003280 self.next(self.state_parameters_start)
3281
3282 # Now entering the parameters section. The rules, formally stated:
3283 #
3284 # * All lines must be indented with spaces only.
3285 # * The first line must be a parameter declaration.
3286 # * The first line must be indented.
3287 # * This first line establishes the indent for parameters.
3288 # * We'll call this number of spaces P (for "parameter").
3289 # * Thenceforth:
3290 # * Lines indented with P spaces specify a parameter.
3291 # * Lines indented with > P spaces are docstrings for the previous
3292 # parameter.
3293 # * We'll call this number of spaces D (for "docstring").
3294 # * All subsequent lines indented with >= D spaces are stored as
3295 # part of the per-parameter docstring.
3296 # * All lines will have the first D spaces of the indent stripped
3297 # before they are stored.
3298 # * It's illegal to have a line starting with a number of spaces X
3299 # such that P < X < D.
3300 # * A line with < P spaces is the first line of the function
3301 # docstring, which ends processing for parameters and per-parameter
3302 # docstrings.
3303 # * The first line of the function docstring must be at the same
3304 # indent as the function declaration.
3305 # * It's illegal to have any line in the parameters section starting
3306 # with X spaces such that F < X < P. (As before, F is the indent
3307 # of the function declaration.)
3308 #
Larry Hastings31826802013-10-19 00:09:25 -07003309 # Also, currently Argument Clinic places the following restrictions on groups:
3310 # * Each group must contain at least one parameter.
3311 # * Each group may contain at most one group, which must be the furthest
3312 # thing in the group from the required parameters. (The nested group
3313 # must be the first in the group when it's before the required
3314 # parameters, and the last thing in the group when after the required
3315 # parameters.)
3316 # * There may be at most one (top-level) group to the left or right of
3317 # the required parameters.
3318 # * You must specify a slash, and it must be after all parameters.
3319 # (In other words: either all parameters are positional-only,
3320 # or none are.)
3321 #
3322 # Said another way:
3323 # * Each group must contain at least one parameter.
3324 # * All left square brackets before the required parameters must be
3325 # consecutive. (You can't have a left square bracket followed
3326 # by a parameter, then another left square bracket. You can't
3327 # have a left square bracket, a parameter, a right square bracket,
3328 # and then a left square bracket.)
3329 # * All right square brackets after the required parameters must be
3330 # consecutive.
3331 #
3332 # These rules are enforced with a single state variable:
3333 # "parameter_state". (Previously the code was a miasma of ifs and
3334 # separate boolean state variables.) The states are:
3335 #
Larry Hastingsc2047262014-01-25 20:43:29 -08003336 # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] / <- line
3337 # 01 2 3 4 5 6 7 <- state transitions
Larry Hastings31826802013-10-19 00:09:25 -07003338 #
3339 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
3340 # 1: ps_left_square_before. left square brackets before required parameters.
3341 # 2: ps_group_before. in a group, before required parameters.
Larry Hastingsc2047262014-01-25 20:43:29 -08003342 # 3: ps_required. required parameters, positional-or-keyword or positional-only
3343 # (we don't know yet). (renumber left groups!)
3344 # 4: ps_optional. positional-or-keyword or positional-only parameters that
3345 # now must have default values.
3346 # 5: ps_group_after. in a group, after required parameters.
3347 # 6: ps_right_square_after. right square brackets after required parameters.
3348 # 7: ps_seen_slash. seen slash.
Larry Hastings31826802013-10-19 00:09:25 -07003349 ps_start, ps_left_square_before, ps_group_before, ps_required, \
Larry Hastingsc2047262014-01-25 20:43:29 -08003350 ps_optional, ps_group_after, ps_right_square_after, ps_seen_slash = range(8)
Larry Hastings31826802013-10-19 00:09:25 -07003351
3352 def state_parameters_start(self, line):
3353 if self.ignore_line(line):
3354 return
3355
3356 # if this line is not indented, we have no parameters
3357 if not self.indent.infer(line):
3358 return self.next(self.state_function_docstring, line)
3359
Larry Hastings2a727912014-01-16 11:32:01 -08003360 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07003361 return self.next(self.state_parameter, line)
3362
3363
3364 def to_required(self):
3365 """
3366 Transition to the "required" parameter state.
3367 """
3368 if self.parameter_state != self.ps_required:
3369 self.parameter_state = self.ps_required
3370 for p in self.function.parameters.values():
3371 p.group = -p.group
3372
3373 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08003374 if self.parameter_continuation:
3375 line = self.parameter_continuation + ' ' + line.lstrip()
3376 self.parameter_continuation = ''
3377
Larry Hastings31826802013-10-19 00:09:25 -07003378 if self.ignore_line(line):
3379 return
3380
3381 assert self.indent.depth == 2
3382 indent = self.indent.infer(line)
3383 if indent == -1:
3384 # we outdented, must be to definition column
3385 return self.next(self.state_function_docstring, line)
3386
3387 if indent == 1:
3388 # we indented, must be to new parameter docstring column
3389 return self.next(self.state_parameter_docstring_start, line)
3390
Larry Hastings2a727912014-01-16 11:32:01 -08003391 line = line.rstrip()
3392 if line.endswith('\\'):
3393 self.parameter_continuation = line[:-1]
3394 return
3395
Larry Hastings31826802013-10-19 00:09:25 -07003396 line = line.lstrip()
3397
3398 if line in ('*', '/', '[', ']'):
3399 self.parse_special_symbol(line)
3400 return
3401
3402 if self.parameter_state in (self.ps_start, self.ps_required):
3403 self.to_required()
3404 elif self.parameter_state == self.ps_left_square_before:
3405 self.parameter_state = self.ps_group_before
3406 elif self.parameter_state == self.ps_group_before:
3407 if not self.group:
3408 self.to_required()
Larry Hastingsc2047262014-01-25 20:43:29 -08003409 elif self.parameter_state in (self.ps_group_after, self.ps_optional):
Larry Hastings31826802013-10-19 00:09:25 -07003410 pass
3411 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003412 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
Larry Hastings31826802013-10-19 00:09:25 -07003413
Larry Hastings2a727912014-01-16 11:32:01 -08003414 base, equals, default = line.rpartition('=')
3415 if not equals:
3416 base = default
3417 default = None
Larry Hastingsc2047262014-01-25 20:43:29 -08003418
Larry Hastings31826802013-10-19 00:09:25 -07003419 module = None
3420 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003421 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003422 module = ast.parse(ast_input)
3423 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003424 try:
Larry Hastingsc2047262014-01-25 20:43:29 -08003425 # the last = was probably inside a function call, like
3426 # i: int(nullable=True)
3427 # so assume there was no actual default value.
Larry Hastings2a727912014-01-16 11:32:01 -08003428 default = None
3429 ast_input = "def x({}): pass".format(line)
3430 module = ast.parse(ast_input)
3431 except SyntaxError:
3432 pass
Larry Hastings31826802013-10-19 00:09:25 -07003433 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003434 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003435
3436 function_args = module.body[0].args
3437 parameter = function_args.args[0]
3438
Larry Hastings16c51912014-01-07 11:53:01 -08003439 parameter_name = parameter.arg
3440 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3441
Larry Hastings2a727912014-01-16 11:32:01 -08003442 if not default:
Larry Hastingsc2047262014-01-25 20:43:29 -08003443 if self.parameter_state == self.ps_optional:
3444 fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!")
Larry Hastings2a727912014-01-16 11:32:01 -08003445 value = unspecified
3446 if 'py_default' in kwargs:
3447 fail("You can't specify py_default without specifying a default value!")
3448 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003449 if self.parameter_state == self.ps_required:
3450 self.parameter_state = self.ps_optional
Larry Hastings2a727912014-01-16 11:32:01 -08003451 default = default.strip()
Zachary Ware021bb872014-01-24 22:52:30 -06003452 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003453 ast_input = "x = {}".format(default)
Larry Hastingsc2047262014-01-25 20:43:29 -08003454 bad = False
Larry Hastings2a727912014-01-16 11:32:01 -08003455 try:
3456 module = ast.parse(ast_input)
3457
Larry Hastings5c661892014-01-24 06:17:25 -08003458 if 'c_default' not in kwargs:
3459 # we can only represent very simple data values in C.
3460 # detect whether default is okay, via a blacklist
3461 # of disallowed ast nodes.
3462 class DetectBadNodes(ast.NodeVisitor):
3463 bad = False
3464 def bad_node(self, node):
3465 self.bad = True
Larry Hastings2a727912014-01-16 11:32:01 -08003466
Larry Hastings5c661892014-01-24 06:17:25 -08003467 # inline function call
3468 visit_Call = bad_node
3469 # inline if statement ("x = 3 if y else z")
3470 visit_IfExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003471
Larry Hastings5c661892014-01-24 06:17:25 -08003472 # comprehensions and generator expressions
3473 visit_ListComp = visit_SetComp = bad_node
3474 visit_DictComp = visit_GeneratorExp = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003475
Larry Hastings5c661892014-01-24 06:17:25 -08003476 # literals for advanced types
3477 visit_Dict = visit_Set = bad_node
3478 visit_List = visit_Tuple = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003479
Larry Hastings5c661892014-01-24 06:17:25 -08003480 # "starred": "a = [1, 2, 3]; *a"
3481 visit_Starred = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003482
Larry Hastings5c661892014-01-24 06:17:25 -08003483 # allow ellipsis, for now
3484 # visit_Ellipsis = bad_node
Larry Hastings2a727912014-01-16 11:32:01 -08003485
Larry Hastings5c661892014-01-24 06:17:25 -08003486 blacklist = DetectBadNodes()
3487 blacklist.visit(module)
3488 bad = blacklist.bad
3489 else:
3490 # if they specify a c_default, we can be more lenient about the default value.
Zachary Ware021bb872014-01-24 22:52:30 -06003491 # but at least make an attempt at ensuring it's a valid expression.
3492 try:
3493 value = eval(default)
3494 if value == unspecified:
3495 fail("'unspecified' is not a legal default value!")
3496 except NameError:
3497 pass # probably a named constant
3498 except Exception as e:
3499 fail("Malformed expression given as default value\n"
3500 "{!r} caused {!r}".format(default, e))
Larry Hastings5c661892014-01-24 06:17:25 -08003501 if bad:
Larry Hastings2a727912014-01-16 11:32:01 -08003502 fail("Unsupported expression as default value: " + repr(default))
3503
3504 expr = module.body[0].value
3505 # mild hack: explicitly support NULL as a default value
3506 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3507 value = NULL
3508 py_default = 'None'
3509 c_default = "NULL"
3510 elif (isinstance(expr, ast.BinOp) or
3511 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3512 c_default = kwargs.get("c_default")
3513 if not (isinstance(c_default, str) and c_default):
3514 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3515 py_default = default
3516 value = unknown
3517 elif isinstance(expr, ast.Attribute):
3518 a = []
3519 n = expr
3520 while isinstance(n, ast.Attribute):
3521 a.append(n.attr)
3522 n = n.value
3523 if not isinstance(n, ast.Name):
3524 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3525 a.append(n.id)
3526 py_default = ".".join(reversed(a))
3527
3528 c_default = kwargs.get("c_default")
3529 if not (isinstance(c_default, str) and c_default):
3530 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3531
3532 try:
3533 value = eval(py_default)
3534 except NameError:
3535 value = unknown
3536 else:
3537 value = ast.literal_eval(expr)
3538 py_default = repr(value)
3539 if isinstance(value, (bool, None.__class__)):
3540 c_default = "Py_" + py_default
3541 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003542 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003543 else:
3544 c_default = py_default
3545
3546 except SyntaxError as e:
3547 fail("Syntax error: " + repr(e.text))
3548 except (ValueError, AttributeError):
3549 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003550 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003551 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003552 if not (isinstance(c_default, str) and c_default):
3553 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3554
Larry Hastings2a727912014-01-16 11:32:01 -08003555 kwargs.setdefault('c_default', c_default)
3556 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003557
Larry Hastings31826802013-10-19 00:09:25 -07003558 dict = legacy_converters if legacy else converters
3559 legacy_str = "legacy " if legacy else ""
3560 if name not in dict:
3561 fail('{} is not a valid {}converter'.format(name, legacy_str))
3562 converter = dict[name](parameter_name, self.function, value, **kwargs)
3563
3564 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
Larry Hastings5c661892014-01-24 06:17:25 -08003565
3566 if isinstance(converter, self_converter):
3567 if len(self.function.parameters) == 1:
3568 if (self.parameter_state != self.ps_required):
3569 fail("A 'self' parameter cannot be marked optional.")
3570 if value is not unspecified:
3571 fail("A 'self' parameter cannot have a default value.")
3572 if self.group:
3573 fail("A 'self' parameter cannot be in an optional group.")
3574 kind = inspect.Parameter.POSITIONAL_ONLY
3575 self.parameter_state = self.ps_start
3576 self.function.parameters.clear()
3577 else:
3578 fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
3579
Larry Hastings31826802013-10-19 00:09:25 -07003580 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003581
3582 if parameter_name in self.function.parameters:
3583 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003584 self.function.parameters[parameter_name] = p
3585
3586 def parse_converter(self, annotation):
3587 if isinstance(annotation, ast.Str):
3588 return annotation.s, True, {}
3589
3590 if isinstance(annotation, ast.Name):
3591 return annotation.id, False, {}
3592
Larry Hastings4a55fc52014-01-12 11:09:57 -08003593 if not isinstance(annotation, ast.Call):
3594 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003595
3596 name = annotation.func.id
3597 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
3598 return name, False, kwargs
3599
3600 def parse_special_symbol(self, symbol):
3601 if self.parameter_state == self.ps_seen_slash:
3602 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
3603
3604 if symbol == '*':
3605 if self.keyword_only:
3606 fail("Function " + self.function.name + " uses '*' more than once.")
3607 self.keyword_only = True
3608 elif symbol == '[':
3609 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3610 self.parameter_state = self.ps_left_square_before
3611 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3612 self.parameter_state = self.ps_group_after
3613 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003614 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
Larry Hastings31826802013-10-19 00:09:25 -07003615 self.group += 1
Larry Hastings581ee362014-01-28 05:00:08 -08003616 self.function.suppress_signature = True
Larry Hastings31826802013-10-19 00:09:25 -07003617 elif symbol == ']':
3618 if not self.group:
3619 fail("Function " + self.function.name + " has a ] without a matching [.")
3620 if not any(p.group == self.group for p in self.function.parameters.values()):
3621 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3622 self.group -= 1
3623 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3624 self.parameter_state = self.ps_group_before
3625 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3626 self.parameter_state = self.ps_right_square_after
3627 else:
Larry Hastingsc2047262014-01-25 20:43:29 -08003628 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
Larry Hastings31826802013-10-19 00:09:25 -07003629 elif symbol == '/':
Larry Hastingsc2047262014-01-25 20:43:29 -08003630 # ps_required and ps_optional are allowed here, that allows positional-only without option groups
Larry Hastings31826802013-10-19 00:09:25 -07003631 # to work (and have default values!)
Larry Hastingsc2047262014-01-25 20:43:29 -08003632 if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
3633 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
Larry Hastings31826802013-10-19 00:09:25 -07003634 if self.keyword_only:
3635 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3636 self.parameter_state = self.ps_seen_slash
3637 # fixup preceeding parameters
3638 for p in self.function.parameters.values():
Larry Hastings5c661892014-01-24 06:17:25 -08003639 if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
Larry Hastings31826802013-10-19 00:09:25 -07003640 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3641 p.kind = inspect.Parameter.POSITIONAL_ONLY
3642
3643 def state_parameter_docstring_start(self, line):
3644 self.parameter_docstring_indent = len(self.indent.margin)
3645 assert self.indent.depth == 3
3646 return self.next(self.state_parameter_docstring, line)
3647
3648 # every line of the docstring must start with at least F spaces,
3649 # where F > P.
3650 # these F spaces will be stripped.
3651 def state_parameter_docstring(self, line):
3652 stripped = line.strip()
3653 if stripped.startswith('#'):
3654 return
3655
3656 indent = self.indent.measure(line)
3657 if indent < self.parameter_docstring_indent:
3658 self.indent.infer(line)
3659 assert self.indent.depth < 3
3660 if self.indent.depth == 2:
3661 # back to a parameter
3662 return self.next(self.state_parameter, line)
3663 assert self.indent.depth == 1
3664 return self.next(self.state_function_docstring, line)
3665
3666 assert self.function.parameters
3667 last_parameter = next(reversed(list(self.function.parameters.values())))
3668
3669 new_docstring = last_parameter.docstring
3670
3671 if new_docstring:
3672 new_docstring += '\n'
3673 if stripped:
3674 new_docstring += self.indent.dedent(line)
3675
3676 last_parameter.docstring = new_docstring
3677
3678 # the final stanza of the DSL is the docstring.
3679 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003680 if self.group:
3681 fail("Function " + self.function.name + " has a ] without a matching [.")
3682
3683 stripped = line.strip()
3684 if stripped.startswith('#'):
3685 return
3686
3687 new_docstring = self.function.docstring
3688 if new_docstring:
3689 new_docstring += "\n"
3690 if stripped:
3691 line = self.indent.dedent(line).rstrip()
3692 else:
3693 line = ''
3694 new_docstring += line
3695 self.function.docstring = new_docstring
3696
3697 def format_docstring(self):
3698 f = self.function
3699
Larry Hastings5c661892014-01-24 06:17:25 -08003700 new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
3701 if new_or_init and not f.docstring:
3702 # don't render a docstring at all, no signature, nothing.
3703 return f.docstring
3704
Larry Hastings31826802013-10-19 00:09:25 -07003705 add, output = text_accumulator()
3706 parameters = list(f.parameters.values())
3707
3708 ##
3709 ## docstring first line
3710 ##
3711
Larry Hastings581ee362014-01-28 05:00:08 -08003712 if not f.suppress_signature:
3713 add('sig=')
Larry Hastings46258262014-01-22 03:05:49 -08003714 else:
Larry Hastings581ee362014-01-28 05:00:08 -08003715 if new_or_init:
3716 assert f.cls
3717 add(f.cls.name)
3718 else:
3719 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07003720 add('(')
3721
3722 # populate "right_bracket_count" field for every parameter
Larry Hastings5c661892014-01-24 06:17:25 -08003723 assert parameters, "We should always have a self parameter. " + repr(f)
3724 assert isinstance(parameters[0].converter, self_converter)
3725 parameters[0].right_bracket_count = 0
3726 parameters_after_self = parameters[1:]
3727 if parameters_after_self:
Larry Hastings31826802013-10-19 00:09:25 -07003728 # for now, the only way Clinic supports positional-only parameters
Larry Hastings5c661892014-01-24 06:17:25 -08003729 # is if all of them are positional-only...
3730 #
3731 # ... except for self! self is always positional-only.
3732
3733 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters_after_self]
3734 if parameters_after_self[0].kind == inspect.Parameter.POSITIONAL_ONLY:
Larry Hastings31826802013-10-19 00:09:25 -07003735 assert all(positional_only_parameters)
3736 for p in parameters:
3737 p.right_bracket_count = abs(p.group)
3738 else:
3739 # don't put any right brackets around non-positional-only parameters, ever.
Larry Hastings5c661892014-01-24 06:17:25 -08003740 for p in parameters_after_self:
Larry Hastings31826802013-10-19 00:09:25 -07003741 p.right_bracket_count = 0
3742
3743 right_bracket_count = 0
3744
3745 def fix_right_bracket_count(desired):
3746 nonlocal right_bracket_count
3747 s = ''
3748 while right_bracket_count < desired:
3749 s += '['
3750 right_bracket_count += 1
3751 while right_bracket_count > desired:
3752 s += ']'
3753 right_bracket_count -= 1
3754 return s
3755
3756 added_star = False
3757 add_comma = False
3758
3759 for p in parameters:
Larry Hastings5c661892014-01-24 06:17:25 -08003760 if not p.converter.show_in_signature:
3761 continue
3762
Larry Hastings31826802013-10-19 00:09:25 -07003763 assert p.name
3764
3765 if p.is_keyword_only() and not added_star:
3766 added_star = True
3767 if add_comma:
3768 add(', ')
3769 add('*')
Larry Hastings5c661892014-01-24 06:17:25 -08003770 add_comma = True
Larry Hastings31826802013-10-19 00:09:25 -07003771
Larry Hastings5c661892014-01-24 06:17:25 -08003772 name = p.converter.signature_name or p.name
Larry Hastings581ee362014-01-28 05:00:08 -08003773
3774 a = []
3775 if isinstance(p.converter, self_converter) and not f.suppress_signature:
3776 # annotate first parameter as being a "self".
3777 #
3778 # if inspect.Signature gets this function, and it's already bound,
3779 # the self parameter will be stripped off.
3780 #
3781 # if it's not bound, it should be marked as positional-only.
3782 a.append('$')
3783 a.append(name)
Larry Hastings31826802013-10-19 00:09:25 -07003784 if p.converter.is_optional():
3785 a.append('=')
Larry Hastingsc4fe0922014-01-19 02:27:34 -08003786 value = p.converter.py_default
3787 if not value:
Larry Hastings66575782014-01-19 03:01:23 -08003788 value = repr(p.converter.default)
Larry Hastingsc4fe0922014-01-19 02:27:34 -08003789 a.append(value)
Larry Hastings31826802013-10-19 00:09:25 -07003790 s = fix_right_bracket_count(p.right_bracket_count)
3791 s += "".join(a)
3792 if add_comma:
3793 add(', ')
3794 add(s)
3795 add_comma = True
3796
3797 add(fix_right_bracket_count(0))
3798 add(')')
3799
Larry Hastings2a727912014-01-16 11:32:01 -08003800 # PEP 8 says:
3801 #
3802 # The Python standard library will not use function annotations
3803 # as that would result in a premature commitment to a particular
3804 # annotation style. Instead, the annotations are left for users
3805 # to discover and experiment with useful annotation styles.
3806 #
3807 # therefore this is commented out:
3808 #
3809 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003810 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08003811 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003812
3813 docstring_first_line = output()
3814
3815 # now fix up the places where the brackets look wrong
3816 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
3817
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003818 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07003819 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003820 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07003821 for p in parameters:
3822 if not p.docstring.strip():
3823 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003824 if spacer_line:
3825 add('\n')
3826 else:
3827 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07003828 add(" ")
3829 add(p.name)
3830 add('\n')
3831 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003832 parameters = output()
3833 if parameters:
3834 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07003835
3836 ##
3837 ## docstring body
3838 ##
3839
3840 docstring = f.docstring.rstrip()
3841 lines = [line.rstrip() for line in docstring.split('\n')]
3842
3843 # Enforce the summary line!
3844 # The first line of a docstring should be a summary of the function.
3845 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
3846 # by itself.
3847 #
3848 # Argument Clinic enforces the following rule:
3849 # * either the docstring is empty,
3850 # * or it must have a summary line.
3851 #
3852 # Guido said Clinic should enforce this:
3853 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
3854
3855 if len(lines) >= 2:
3856 if lines[1]:
3857 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
3858 "Every non-blank function docstring must start with\n" +
3859 "a single line summary followed by an empty line.")
3860 elif len(lines) == 1:
3861 # the docstring is only one line right now--the summary line.
3862 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003863 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07003864 lines.append('')
3865
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003866 parameters_marker_count = len(docstring.split('{parameters}')) - 1
3867 if parameters_marker_count > 1:
3868 fail('You may not specify {parameters} more than once in a docstring!')
3869
3870 if not parameters_marker_count:
3871 # insert after summary line
3872 lines.insert(2, '{parameters}')
3873
3874 # insert at front of docstring
3875 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07003876
3877 docstring = "\n".join(lines)
3878
3879 add(docstring)
3880 docstring = output()
3881
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003882 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07003883 docstring = docstring.rstrip()
3884
3885 return docstring
3886
3887 def state_terminal(self, line):
3888 """
3889 Called when processing the block is done.
3890 """
3891 assert not line
3892
3893 if not self.function:
3894 return
3895
3896 if self.keyword_only:
3897 values = self.function.parameters.values()
3898 if not values:
3899 no_parameter_after_star = True
3900 else:
3901 last_parameter = next(reversed(list(values)))
3902 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
3903 if no_parameter_after_star:
3904 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
3905
3906 # remove trailing whitespace from all parameter docstrings
3907 for name, value in self.function.parameters.items():
3908 if not value:
3909 continue
3910 value.docstring = value.docstring.rstrip()
3911
3912 self.function.docstring = self.format_docstring()
3913
3914
Larry Hastings5c661892014-01-24 06:17:25 -08003915
3916
Larry Hastings31826802013-10-19 00:09:25 -07003917# maps strings to callables.
3918# the callable should return an object
3919# that implements the clinic parser
3920# interface (__init__ and parse).
3921#
3922# example parsers:
3923# "clinic", handles the Clinic DSL
3924# "python", handles running Python code
3925#
3926parsers = {'clinic' : DSLParser, 'python': PythonParser}
3927
3928
3929clinic = None
3930
3931
3932def main(argv):
3933 import sys
3934
3935 if sys.version_info.major < 3 or sys.version_info.minor < 3:
3936 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
3937
3938 import argparse
3939 cmdline = argparse.ArgumentParser()
3940 cmdline.add_argument("-f", "--force", action='store_true')
3941 cmdline.add_argument("-o", "--output", type=str)
Larry Hastings5c661892014-01-24 06:17:25 -08003942 cmdline.add_argument("-v", "--verbose", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07003943 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003944 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07003945 cmdline.add_argument("filename", type=str, nargs="*")
3946 ns = cmdline.parse_args(argv)
3947
3948 if ns.converters:
3949 if ns.filename:
3950 print("Usage error: can't specify --converters and a filename at the same time.")
3951 print()
3952 cmdline.print_usage()
3953 sys.exit(-1)
3954 converters = []
3955 return_converters = []
3956 ignored = set("""
3957 add_c_converter
3958 add_c_return_converter
3959 add_default_legacy_c_converter
3960 add_legacy_c_converter
3961 """.strip().split())
3962 module = globals()
3963 for name in module:
3964 for suffix, ids in (
3965 ("_return_converter", return_converters),
3966 ("_converter", converters),
3967 ):
3968 if name in ignored:
3969 continue
3970 if name.endswith(suffix):
3971 ids.append((name, name[:-len(suffix)]))
3972 break
3973 print()
3974
3975 print("Legacy converters:")
3976 legacy = sorted(legacy_converters)
3977 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
3978 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
3979 print()
3980
3981 for title, attribute, ids in (
3982 ("Converters", 'converter_init', converters),
3983 ("Return converters", 'return_converter_init', return_converters),
3984 ):
3985 print(title + ":")
3986 longest = -1
3987 for name, short_name in ids:
3988 longest = max(longest, len(short_name))
3989 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
3990 cls = module[name]
3991 callable = getattr(cls, attribute, None)
3992 if not callable:
3993 continue
3994 signature = inspect.signature(callable)
3995 parameters = []
3996 for parameter_name, parameter in signature.parameters.items():
3997 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
3998 if parameter.default != inspect.Parameter.empty:
3999 s = '{}={!r}'.format(parameter_name, parameter.default)
4000 else:
4001 s = parameter_name
4002 parameters.append(s)
4003 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07004004 print()
Larry Hastings2a727912014-01-16 11:32:01 -08004005 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
4006 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07004007 sys.exit(0)
4008
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004009 if ns.make:
4010 if ns.output or ns.filename:
4011 print("Usage error: can't use -o or filenames with --make.")
4012 print()
4013 cmdline.print_usage()
4014 sys.exit(-1)
4015 for root, dirs, files in os.walk('.'):
Larry Hastings5c661892014-01-24 06:17:25 -08004016 for rcs_dir in ('.svn', '.git', '.hg', 'build'):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004017 if rcs_dir in dirs:
4018 dirs.remove(rcs_dir)
4019 for filename in files:
Larry Hastings5c661892014-01-24 06:17:25 -08004020 if not (filename.endswith('.c') or filename.endswith('.h')):
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004021 continue
4022 path = os.path.join(root, filename)
Larry Hastings5c661892014-01-24 06:17:25 -08004023 if ns.verbose:
4024 print(path)
Larry Hastings581ee362014-01-28 05:00:08 -08004025 parse_file(path, force=ns.force, verify=not ns.force)
Larry Hastingsdcd340e2013-11-23 14:58:45 -08004026 return
4027
Larry Hastings31826802013-10-19 00:09:25 -07004028 if not ns.filename:
4029 cmdline.print_usage()
4030 sys.exit(-1)
4031
4032 if ns.output and len(ns.filename) > 1:
4033 print("Usage error: can't use -o with multiple filenames.")
4034 print()
4035 cmdline.print_usage()
4036 sys.exit(-1)
4037
4038 for filename in ns.filename:
Larry Hastings5c661892014-01-24 06:17:25 -08004039 if ns.verbose:
4040 print(filename)
Larry Hastings581ee362014-01-28 05:00:08 -08004041 parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
Larry Hastings31826802013-10-19 00:09:25 -07004042
4043
4044if __name__ == "__main__":
4045 sys.exit(main(sys.argv[1:]))