blob: ba0bc174ce2116e45691a66a16871e362cd73d12 [file] [log] [blame]
Larry Hastings31826802013-10-19 00:09:25 -07001#!/usr/bin/env python3
2#
3# Argument Clinic
4# Copyright 2012-2013 by Larry Hastings.
5# Licensed to the PSF under a contributor agreement.
6#
7
8import abc
9import ast
10import atexit
Larry Hastings31826802013-10-19 00:09:25 -070011import collections
12import contextlib
13import functools
14import hashlib
15import inspect
16import io
17import itertools
18import os
Larry Hastingsbebf7352014-01-17 17:47:17 -080019import pprint
Larry Hastings31826802013-10-19 00:09:25 -070020import re
21import shlex
22import sys
23import tempfile
24import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010025import traceback
Larry Hastingsbebf7352014-01-17 17:47:17 -080026import uuid
Larry Hastings31826802013-10-19 00:09:25 -070027
Larry Hastings31826802013-10-19 00:09:25 -070028# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070029#
30# soon:
31#
32# * allow mixing any two of {positional-only, positional-or-keyword,
33# keyword-only}
34# * dict constructor uses positional-only and keyword-only
35# * max and min use positional only with an optional group
36# and keyword-only
37#
Larry Hastings31826802013-10-19 00:09:25 -070038
Larry Hastingsebdcb502013-11-23 14:54:00 -080039version = '1'
40
Larry Hastings31826802013-10-19 00:09:25 -070041_empty = inspect._empty
42_void = inspect._void
43
Larry Hastings4a55fc52014-01-12 11:09:57 -080044NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070045
46class Unspecified:
47 def __repr__(self):
48 return '<Unspecified>'
49
50unspecified = Unspecified()
51
52
53class Null:
54 def __repr__(self):
55 return '<Null>'
56
57NULL = Null()
58
59
Larry Hastings2a727912014-01-16 11:32:01 -080060class Unknown:
61 def __repr__(self):
62 return '<Unknown>'
63
64unknown = Unknown()
65
66
Larry Hastings31826802013-10-19 00:09:25 -070067def _text_accumulator():
68 text = []
69 def output():
70 s = ''.join(text)
71 text.clear()
72 return s
73 return text, text.append, output
74
75
76def text_accumulator():
77 """
78 Creates a simple text accumulator / joiner.
79
80 Returns a pair of callables:
81 append, output
82 "append" appends a string to the accumulator.
83 "output" returns the contents of the accumulator
84 joined together (''.join(accumulator)) and
85 empties the accumulator.
86 """
87 text, append, output = _text_accumulator()
88 return append, output
89
90
Larry Hastingsbebf7352014-01-17 17:47:17 -080091def warn_or_fail(fail=False, *args, filename=None, line_number=None):
Larry Hastings31826802013-10-19 00:09:25 -070092 joined = " ".join([str(a) for a in args])
93 add, output = text_accumulator()
Larry Hastingsbebf7352014-01-17 17:47:17 -080094 if fail:
95 add("Error")
96 else:
97 add("Warning")
Larry Hastings31826802013-10-19 00:09:25 -070098 if clinic:
99 if filename is None:
100 filename = clinic.filename
101 if clinic.block_parser and (line_number is None):
102 line_number = clinic.block_parser.line_number
103 if filename is not None:
104 add(' in file "' + filename + '"')
105 if line_number is not None:
106 add(" on line " + str(line_number))
107 add(':\n')
108 add(joined)
109 print(output())
Larry Hastingsbebf7352014-01-17 17:47:17 -0800110 if fail:
111 sys.exit(-1)
Larry Hastings31826802013-10-19 00:09:25 -0700112
113
Larry Hastingsbebf7352014-01-17 17:47:17 -0800114def warn(*args, filename=None, line_number=None):
115 return warn_or_fail(False, *args, filename=filename, line_number=line_number)
116
117def fail(*args, filename=None, line_number=None):
118 return warn_or_fail(True, *args, filename=filename, line_number=line_number)
119
Larry Hastings31826802013-10-19 00:09:25 -0700120
121def quoted_for_c_string(s):
122 for old, new in (
123 ('"', '\\"'),
124 ("'", "\\'"),
125 ):
126 s = s.replace(old, new)
127 return s
128
Larry Hastings4903e002014-01-18 00:26:16 -0800129def c_repr(s):
130 return '"' + s + '"'
131
132
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700133is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
134
135def is_legal_py_identifier(s):
136 return all(is_legal_c_identifier(field) for field in s.split('.'))
137
Larry Hastingsbebf7352014-01-17 17:47:17 -0800138# identifiers that are okay in Python but aren't a good idea in C.
139# so if they're used Argument Clinic will add "_value" to the end
140# of the name in C.
Larry Hastings31826802013-10-19 00:09:25 -0700141c_keywords = set("""
Larry Hastingsbebf7352014-01-17 17:47:17 -0800142asm auto break case char cls const continue default do double
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800143else enum extern float for goto if inline int long module null
144register return self short signed sizeof static struct switch
Larry Hastingsbebf7352014-01-17 17:47:17 -0800145typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700146""".strip().split())
147
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700148def ensure_legal_c_identifier(s):
149 # for now, just complain if what we're given isn't legal
150 if not is_legal_c_identifier(s):
151 fail("Illegal C identifier: {}".format(s))
152 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700153 if s in c_keywords:
154 return s + "_value"
155 return s
156
157def rstrip_lines(s):
158 text, add, output = _text_accumulator()
159 for line in s.split('\n'):
160 add(line.rstrip())
161 add('\n')
162 text.pop()
163 return output()
164
165def linear_format(s, **kwargs):
166 """
167 Perform str.format-like substitution, except:
168 * The strings substituted must be on lines by
169 themselves. (This line is the "source line".)
170 * If the substitution text is empty, the source line
171 is removed in the output.
172 * If the substitution text is not empty:
173 * Each line of the substituted text is indented
174 by the indent of the source line.
175 * A newline will be added to the end.
176 """
177
178 add, output = text_accumulator()
179 for line in s.split('\n'):
180 indent, curly, trailing = line.partition('{')
181 if not curly:
182 add(line)
183 add('\n')
184 continue
185
186 name, curl, trailing = trailing.partition('}')
187 if not curly or name not in kwargs:
188 add(line)
189 add('\n')
190 continue
191
192 if trailing:
193 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
194 if indent.strip():
195 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
196
197 value = kwargs[name]
198 if not value:
199 continue
200
201 value = textwrap.indent(rstrip_lines(value), indent)
202 add(value)
203 add('\n')
204
205 return output()[:-1]
206
Larry Hastingsbebf7352014-01-17 17:47:17 -0800207def indent_all_lines(s, prefix):
208 """
209 Returns 's', with 'prefix' prepended to all lines.
210
211 If the last line is empty, prefix is not prepended
212 to it. (If s is blank, returns s unchanged.)
213
214 (textwrap.indent only adds to non-blank lines.)
215 """
216 split = s.split('\n')
217 last = split.pop()
218 final = []
219 for line in split:
220 final.append(prefix)
221 final.append(line)
222 final.append('\n')
223 if last:
224 final.append(prefix)
225 final.append(last)
226 return ''.join(final)
227
228def suffix_all_lines(s, suffix):
229 """
230 Returns 's', with 'suffix' appended to all lines.
231
232 If the last line is empty, suffix is not appended
233 to it. (If s is blank, returns s unchanged.)
234 """
235 split = s.split('\n')
236 last = split.pop()
237 final = []
238 for line in split:
239 final.append(line)
240 final.append(suffix)
241 final.append('\n')
242 if last:
243 final.append(last)
244 final.append(suffix)
245 return ''.join(final)
246
247
Larry Hastingsebdcb502013-11-23 14:54:00 -0800248def version_splitter(s):
249 """Splits a version string into a tuple of integers.
250
251 The following ASCII characters are allowed, and employ
252 the following conversions:
253 a -> -3
254 b -> -2
255 c -> -1
256 (This permits Python-style version strings such as "1.4b3".)
257 """
258 version = []
259 accumulator = []
260 def flush():
261 if not accumulator:
Larry Hastings2a727912014-01-16 11:32:01 -0800262 raise ValueError('Unsupported version string: ' + repr(s))
Larry Hastingsebdcb502013-11-23 14:54:00 -0800263 version.append(int(''.join(accumulator)))
264 accumulator.clear()
265
266 for c in s:
267 if c.isdigit():
268 accumulator.append(c)
269 elif c == '.':
270 flush()
271 elif c in 'abc':
272 flush()
273 version.append('abc'.index(c) - 3)
274 else:
275 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
276 flush()
277 return tuple(version)
278
279def version_comparitor(version1, version2):
280 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
281 for i, (a, b) in enumerate(iterator):
282 if a < b:
283 return -1
284 if a > b:
285 return 1
286 return 0
287
Larry Hastings31826802013-10-19 00:09:25 -0700288
289class CRenderData:
290 def __init__(self):
291
292 # The C statements to declare variables.
293 # Should be full lines with \n eol characters.
294 self.declarations = []
295
296 # The C statements required to initialize the variables before the parse call.
297 # Should be full lines with \n eol characters.
298 self.initializers = []
299
300 # The entries for the "keywords" array for PyArg_ParseTuple.
301 # Should be individual strings representing the names.
302 self.keywords = []
303
304 # The "format units" for PyArg_ParseTuple.
305 # Should be individual strings that will get
306 self.format_units = []
307
308 # The varargs arguments for PyArg_ParseTuple.
309 self.parse_arguments = []
310
311 # The parameter declarations for the impl function.
312 self.impl_parameters = []
313
314 # The arguments to the impl function at the time it's called.
315 self.impl_arguments = []
316
317 # For return converters: the name of the variable that
318 # should receive the value returned by the impl.
319 self.return_value = "return_value"
320
321 # For return converters: the code to convert the return
322 # value from the parse function. This is also where
323 # you should check the _return_value for errors, and
324 # "goto exit" if there are any.
325 self.return_conversion = []
326
327 # The C statements required to clean up after the impl call.
328 self.cleanup = []
329
330
331class Language(metaclass=abc.ABCMeta):
332
333 start_line = ""
334 body_prefix = ""
335 stop_line = ""
336 checksum_line = ""
337
338 @abc.abstractmethod
Larry Hastingsbebf7352014-01-17 17:47:17 -0800339 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700340 pass
341
342 def validate(self):
343 def assert_only_one(field, token='dsl_name'):
344 line = getattr(self, field)
345 token = '{' + token + '}'
346 if len(line.split(token)) != 2:
347 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
348 assert_only_one('start_line')
349 assert_only_one('stop_line')
350 assert_only_one('checksum_line')
351 assert_only_one('checksum_line', 'checksum')
352
353 if len(self.body_prefix.split('{dsl_name}')) >= 3:
354 fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
355
356
357
358class PythonLanguage(Language):
359
360 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800361 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700362 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800363 stop_line = "#[{dsl_name} start generated code]*/"
364 checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700365
366
367def permute_left_option_groups(l):
368 """
369 Given [1, 2, 3], should yield:
370 ()
371 (3,)
372 (2, 3)
373 (1, 2, 3)
374 """
375 yield tuple()
376 accumulator = []
377 for group in reversed(l):
378 accumulator = list(group) + accumulator
379 yield tuple(accumulator)
380
381
382def permute_right_option_groups(l):
383 """
384 Given [1, 2, 3], should yield:
385 ()
386 (1,)
387 (1, 2)
388 (1, 2, 3)
389 """
390 yield tuple()
391 accumulator = []
392 for group in l:
393 accumulator.extend(group)
394 yield tuple(accumulator)
395
396
397def permute_optional_groups(left, required, right):
398 """
399 Generator function that computes the set of acceptable
400 argument lists for the provided iterables of
401 argument groups. (Actually it generates a tuple of tuples.)
402
403 Algorithm: prefer left options over right options.
404
405 If required is empty, left must also be empty.
406 """
407 required = tuple(required)
408 result = []
409
410 if not required:
411 assert not left
412
413 accumulator = []
414 counts = set()
415 for r in permute_right_option_groups(right):
416 for l in permute_left_option_groups(left):
417 t = l + required + r
418 if len(t) in counts:
419 continue
420 counts.add(len(t))
421 accumulator.append(t)
422
423 accumulator.sort(key=len)
424 return tuple(accumulator)
425
426
427class CLanguage(Language):
428
Larry Hastings61272b72014-01-07 12:41:53 -0800429 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700430 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800431 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700432 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800433 stop_line = "[{dsl_name} start generated code]*/"
434 checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700435
Larry Hastingsbebf7352014-01-17 17:47:17 -0800436 def render(self, clinic, signatures):
Larry Hastings31826802013-10-19 00:09:25 -0700437 function = None
438 for o in signatures:
439 if isinstance(o, Function):
440 if function:
441 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
442 function = o
Larry Hastingsbebf7352014-01-17 17:47:17 -0800443 return self.render_function(clinic, function)
Larry Hastings31826802013-10-19 00:09:25 -0700444
445 def docstring_for_c_string(self, f):
446 text, add, output = _text_accumulator()
447 # turn docstring into a properly quoted C string
448 for line in f.docstring.split('\n'):
449 add('"')
450 add(quoted_for_c_string(line))
451 add('\\n"\n')
452
453 text.pop()
454 add('"')
455 return ''.join(text)
456
Larry Hastings31826802013-10-19 00:09:25 -0700457
Larry Hastingsbebf7352014-01-17 17:47:17 -0800458 def output_templates(self, f):
459 parameters = list(f.parameters.values())
460 converters = [p.converter for p in parameters]
461
462 has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
463 default_return_converter = (not f.return_converter or
464 f.return_converter.type == 'PyObject *')
465
466 positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY)
467 all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
468 first_optional = len(parameters)
469 for i, p in enumerate(parameters):
470 c = p.converter
471 if type(c) != object_converter:
472 break
473 if c.format_unit != 'O':
474 break
475 if p.default is not unspecified:
476 first_optional = min(first_optional, i)
477 else:
478 all_boring_objects = True
479
480 meth_o = (len(parameters) == 1 and
481 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
482 not converters[0].is_optional() and
483 isinstance(converters[0], object_converter) and
484 converters[0].format_unit == 'O')
485
486
487 # we have to set seven things before we're done:
488 #
489 # docstring_prototype
490 # docstring_definition
491 # impl_prototype
492 # methoddef_define
493 # parser_prototype
494 # parser_definition
495 # impl_definition
496 #
497 # since impl_prototype is always just impl_definition + ';'
498 # we just define impl_definition at the top
499
500 docstring_prototype = "PyDoc_VAR({c_basename}__doc__);"
501
502 docstring_definition = """
Larry Hastings31826802013-10-19 00:09:25 -0700503PyDoc_STRVAR({c_basename}__doc__,
504{docstring});
Larry Hastingsbebf7352014-01-17 17:47:17 -0800505""".strip()
Larry Hastings31826802013-10-19 00:09:25 -0700506
Larry Hastingsbebf7352014-01-17 17:47:17 -0800507 impl_definition = """
Larry Hastings31826802013-10-19 00:09:25 -0700508static {impl_return_type}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800509{c_basename}_impl({impl_parameters})""".strip()
Larry Hastings31826802013-10-19 00:09:25 -0700510
Larry Hastingsbebf7352014-01-17 17:47:17 -0800511 impl_prototype = parser_prototype = parser_definition = None
512
513 def meth_varargs():
514 nonlocal flags
515 nonlocal parser_prototype
516
517 flags = "METH_VARARGS"
518
519 parser_prototype = """
520static PyObject *
521{c_basename}({self_type}{self_name}, PyObject *args)
522""".strip()
523
524 if not parameters:
525 # no parameters, METH_NOARGS
526
527 flags = "METH_NOARGS"
528
529 parser_prototype = """
Larry Hastings31826802013-10-19 00:09:25 -0700530static PyObject *
Larry Hastings3cceb382014-01-04 11:09:09 -0800531{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
Larry Hastingsbebf7352014-01-17 17:47:17 -0800532""".strip()
533
534 if default_return_converter:
535 parser_definition = parser_prototype + """
536{{
537 return {c_basename}_impl({impl_arguments});
538}}
539""".rstrip()
540 else:
541 parser_definition = parser_prototype + """
Larry Hastings31826802013-10-19 00:09:25 -0700542{{
543 PyObject *return_value = NULL;
544 {declarations}
545 {initializers}
546
547 {return_value} = {c_basename}_impl({impl_arguments});
548 {return_conversion}
549
550{exit_label}
551 {cleanup}
552 return return_value;
553}}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800554""".rstrip()
Larry Hastings31826802013-10-19 00:09:25 -0700555
Larry Hastingsbebf7352014-01-17 17:47:17 -0800556 elif meth_o:
557 if default_return_converter:
558 # maps perfectly to METH_O, doesn't need a return converter,
559 # so we skip the parse function and call
560 # directly into the impl function
Larry Hastings31826802013-10-19 00:09:25 -0700561
Larry Hastingsbebf7352014-01-17 17:47:17 -0800562 # SLIGHT HACK
563 # METH_O uses {impl_parameters} for the parser.
564
565 flags = "METH_O"
566
567 impl_definition = """
Larry Hastings31826802013-10-19 00:09:25 -0700568static PyObject *
569{c_basename}({impl_parameters})
Larry Hastingsbebf7352014-01-17 17:47:17 -0800570""".strip()
Larry Hastings31826802013-10-19 00:09:25 -0700571
Larry Hastingsbebf7352014-01-17 17:47:17 -0800572 impl_prototype = parser_prototype = parser_definition = ''
Larry Hastings31826802013-10-19 00:09:25 -0700573
Larry Hastingsbebf7352014-01-17 17:47:17 -0800574 else:
575 # SLIGHT HACK
576 # METH_O uses {impl_parameters} for the parser.
577
578 flags = "METH_O"
579
580 parser_prototype = """
Larry Hastings31826802013-10-19 00:09:25 -0700581static PyObject *
582{c_basename}({impl_parameters})
Larry Hastingsbebf7352014-01-17 17:47:17 -0800583""".strip()
584
585 parser_definition = parser_prototype + """
Larry Hastings31826802013-10-19 00:09:25 -0700586{{
587 PyObject *return_value = NULL;
588 {declarations}
589 {initializers}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800590
Larry Hastings31826802013-10-19 00:09:25 -0700591 _return_value = {c_basename}_impl({impl_arguments});
592 {return_conversion}
593
594{exit_label}
595 {cleanup}
596 return return_value;
597}}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800598""".rstrip()
Larry Hastings31826802013-10-19 00:09:25 -0700599
Larry Hastingsbebf7352014-01-17 17:47:17 -0800600 elif has_option_groups:
601 # positional parameters with option groups
602 # (we have to generate lots of PyArg_ParseTuple calls
603 # in a big switch statement)
Larry Hastings31826802013-10-19 00:09:25 -0700604
Larry Hastingsbebf7352014-01-17 17:47:17 -0800605 meth_varargs()
Larry Hastings31826802013-10-19 00:09:25 -0700606
Larry Hastingsbebf7352014-01-17 17:47:17 -0800607 parser_definition = parser_prototype + """
Larry Hastings31826802013-10-19 00:09:25 -0700608{{
609 PyObject *return_value = NULL;
610 {declarations}
611 {initializers}
612
613 {option_group_parsing}
614 {return_value} = {c_basename}_impl({impl_arguments});
615 {return_conversion}
616
617{exit_label}
618 {cleanup}
619 return return_value;
620}}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800621""".rstrip()
Larry Hastings31826802013-10-19 00:09:25 -0700622
Larry Hastingsbebf7352014-01-17 17:47:17 -0800623 elif positional and all_boring_objects:
624 # positional-only, but no option groups,
625 # and nothing but normal objects:
626 # PyArg_UnpackTuple!
Larry Hastings31826802013-10-19 00:09:25 -0700627
Larry Hastingsbebf7352014-01-17 17:47:17 -0800628 meth_varargs()
Larry Hastings31826802013-10-19 00:09:25 -0700629
Larry Hastingsbebf7352014-01-17 17:47:17 -0800630 # substitute in the min and max by hand right here
631 assert parameters
632 min_o = first_optional
633 max_o = len(parameters)
634 if isinstance(parameters[0].converter, self_converter):
635 min_o -= 1
636 max_o -= 1
637 min_o = str(min_o)
638 max_o = str(max_o)
639
640 parser_definition = parser_prototype + """
641{{
642 PyObject *return_value = NULL;
643 {declarations}
644 {initializers}
645
646 if (!PyArg_UnpackTuple(args, "{name}",
647 {min}, {max},
648 {parse_arguments}))
649 goto exit;
650 {return_value} = {c_basename}_impl({impl_arguments});
651 {return_conversion}
652
653exit:
654 {cleanup}
655 return return_value;
656}}
657""".rstrip().replace('{min}', min_o).replace('{max}', max_o)
658
659 elif positional:
660 # positional-only, but no option groups
661 # we only need one call to PyArg_ParseTuple
662
663 meth_varargs()
664
665 parser_definition = parser_prototype + """
666{{
667 PyObject *return_value = NULL;
668 {declarations}
669 {initializers}
670
671 if (!PyArg_ParseTuple(args,
672 "{format_units}:{name}",
673 {parse_arguments}))
674 goto exit;
675 {return_value} = {c_basename}_impl({impl_arguments});
676 {return_conversion}
677
678exit:
679 {cleanup}
680 return return_value;
681}}
682""".rstrip()
683
684 else:
685 # positional-or-keyword arguments
686 flags = "METH_VARARGS|METH_KEYWORDS"
687
688 parser_prototype = """
Larry Hastings31826802013-10-19 00:09:25 -0700689static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800690{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800691""".strip()
692
693 parser_definition = parser_prototype + """
Larry Hastings31826802013-10-19 00:09:25 -0700694{{
695 PyObject *return_value = NULL;
696 static char *_keywords[] = {{{keywords}, NULL}};
697 {declarations}
698 {initializers}
699
700 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
701 "{format_units}:{name}", _keywords,
702 {parse_arguments}))
703 goto exit;
704 {return_value} = {c_basename}_impl({impl_arguments});
705 {return_conversion}
706
Larry Hastingsbebf7352014-01-17 17:47:17 -0800707exit:
Larry Hastings31826802013-10-19 00:09:25 -0700708 {cleanup}
709 return return_value;
710}}
Larry Hastingsbebf7352014-01-17 17:47:17 -0800711""".rstrip()
Larry Hastings31826802013-10-19 00:09:25 -0700712
Larry Hastingsbebf7352014-01-17 17:47:17 -0800713 if f.methoddef_flags:
714 assert flags
715 flags += '|' + f.methoddef_flags
Larry Hastings31826802013-10-19 00:09:25 -0700716
Larry Hastingsbebf7352014-01-17 17:47:17 -0800717 methoddef_define = """
718#define {methoddef_name} \\
719 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
720""".strip().replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700721
Larry Hastingsbebf7352014-01-17 17:47:17 -0800722 # parser_prototype mustn't be None, but it could be an empty string.
723 assert parser_prototype is not None
724 assert not parser_prototype.endswith(';')
Larry Hastings31826802013-10-19 00:09:25 -0700725
Larry Hastingsbebf7352014-01-17 17:47:17 -0800726 if parser_prototype:
727 parser_prototype += ';'
Larry Hastings31826802013-10-19 00:09:25 -0700728
Larry Hastingsbebf7352014-01-17 17:47:17 -0800729 assert impl_definition
730 if impl_prototype is None:
731 impl_prototype = impl_definition + ";"
Larry Hastings31826802013-10-19 00:09:25 -0700732
Larry Hastingsbebf7352014-01-17 17:47:17 -0800733 # __new__ and __init__ don't need methoddefs
734 if f.kind in (METHOD_NEW, METHOD_INIT):
735 methoddef_define = ''
736
737 d = {
738 "docstring_prototype" : docstring_prototype,
739 "docstring_definition" : docstring_definition,
740 "impl_prototype" : impl_prototype,
741 "methoddef_define" : methoddef_define,
742 "parser_prototype" : parser_prototype,
743 "parser_definition" : parser_definition,
744 "impl_definition" : impl_definition,
745 }
746
747 d2 = {}
748 for name, value in d.items():
749 if value:
750 value = '\n' + value + '\n'
751 d2[name] = value
752 return d2
Larry Hastings31826802013-10-19 00:09:25 -0700753
754 @staticmethod
755 def group_to_variable_name(group):
756 adjective = "left_" if group < 0 else "right_"
757 return "group_" + adjective + str(abs(group))
758
759 def render_option_group_parsing(self, f, template_dict):
760 # positional only, grouped, optional arguments!
761 # can be optional on the left or right.
762 # here's an example:
763 #
764 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
765 #
766 # Here group D are required, and all other groups are optional.
767 # (Group D's "group" is actually None.)
768 # We can figure out which sets of arguments we have based on
769 # how many arguments are in the tuple.
770 #
771 # Note that you need to count up on both sides. For example,
772 # you could have groups C+D, or C+D+E, or C+D+E+F.
773 #
774 # What if the number of arguments leads us to an ambiguous result?
775 # Clinic prefers groups on the left. So in the above example,
776 # five arguments would map to B+C, not C+D.
777
778 add, output = text_accumulator()
779 parameters = list(f.parameters.values())
780
781 groups = []
782 group = None
783 left = []
784 right = []
785 required = []
786 last = unspecified
787
788 for p in parameters:
789 group_id = p.group
790 if group_id != last:
791 last = group_id
792 group = []
793 if group_id < 0:
794 left.append(group)
795 elif group_id == 0:
796 group = required
797 else:
798 right.append(group)
799 group.append(p)
800
801 count_min = sys.maxsize
802 count_max = -1
803
Larry Hastings2a727912014-01-16 11:32:01 -0800804 add("switch (PyTuple_GET_SIZE(args)) {{\n")
Larry Hastings31826802013-10-19 00:09:25 -0700805 for subset in permute_optional_groups(left, required, right):
806 count = len(subset)
807 count_min = min(count_min, count)
808 count_max = max(count_max, count)
809
Larry Hastings583baa82014-01-12 08:49:30 -0800810 if count == 0:
811 add(""" case 0:
812 break;
813""")
814 continue
815
Larry Hastings31826802013-10-19 00:09:25 -0700816 group_ids = {p.group for p in subset} # eliminate duplicates
817 d = {}
818 d['count'] = count
819 d['name'] = f.name
820 d['groups'] = sorted(group_ids)
821 d['format_units'] = "".join(p.converter.format_unit for p in subset)
822
823 parse_arguments = []
824 for p in subset:
825 p.converter.parse_argument(parse_arguments)
826 d['parse_arguments'] = ", ".join(parse_arguments)
827
828 group_ids.discard(0)
829 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
830 lines = "\n".join(lines)
831
832 s = """
833 case {count}:
834 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
835 return NULL;
836 {group_booleans}
837 break;
838"""[1:]
839 s = linear_format(s, group_booleans=lines)
840 s = s.format_map(d)
841 add(s)
842
843 add(" default:\n")
844 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
845 add(s.format(f.full_name, count_min, count_max))
846 add(' return NULL;\n')
847 add("}}")
848 template_dict['option_group_parsing'] = output()
849
Larry Hastingsbebf7352014-01-17 17:47:17 -0800850 def render_function(self, clinic, f):
Larry Hastings31826802013-10-19 00:09:25 -0700851 if not f:
852 return ""
853
854 add, output = text_accumulator()
855 data = CRenderData()
856
Larry Hastings31826802013-10-19 00:09:25 -0700857 parameters = list(f.parameters.values())
858 converters = [p.converter for p in parameters]
859
860 template_dict = {}
861
862 full_name = f.full_name
863 template_dict['full_name'] = full_name
864
865 name = full_name.rpartition('.')[2]
866 template_dict['name'] = name
867
Larry Hastings8666e652014-01-12 14:12:59 -0800868 if f.c_basename:
869 c_basename = f.c_basename
870 else:
871 fields = full_name.split(".")
872 if fields[-1] == '__new__':
873 fields.pop()
874 c_basename = "_".join(fields)
Larry Hastings31826802013-10-19 00:09:25 -0700875 template_dict['c_basename'] = c_basename
876
877 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
878 template_dict['methoddef_name'] = methoddef_name
879
880 template_dict['docstring'] = self.docstring_for_c_string(f)
881
Larry Hastings31826802013-10-19 00:09:25 -0700882 positional = has_option_groups = False
883
884 if parameters:
885 last_group = 0
886
887 for p in parameters:
888 c = p.converter
889
890 # insert group variable
891 group = p.group
892 if last_group != group:
893 last_group = group
894 if group:
895 group_name = self.group_to_variable_name(group)
896 data.impl_arguments.append(group_name)
897 data.declarations.append("int " + group_name + " = 0;")
898 data.impl_parameters.append("int " + group_name)
899 has_option_groups = True
900 c.render(p, data)
901
902 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
Larry Hastings4a55fc52014-01-12 11:09:57 -0800903 if has_option_groups and (not positional):
904 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
Larry Hastings31826802013-10-19 00:09:25 -0700905
Larry Hastingsbebf7352014-01-17 17:47:17 -0800906 # HACK
907 # when we're METH_O, but have a custom
908 # return converter, we use
909 # "impl_parameters" for the parsing
910 # function because that works better.
911 # but that means we must supress actually
912 # declaring the impl's parameters as variables
913 # in the parsing function. but since it's
914 # METH_O, we only have one anyway, so we don't
915 # have any problem finding it.
916 default_return_converter = (not f.return_converter or
917 f.return_converter.type == 'PyObject *')
918 if (len(parameters) == 1 and
919 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
920 not converters[0].is_optional() and
921 isinstance(converters[0], object_converter) and
922 converters[0].format_unit == 'O' and
923 not default_return_converter):
924
925 data.declarations.pop(0)
926
Larry Hastingsebdcb502013-11-23 14:54:00 -0800927 # now insert our "self" (or whatever) parameters
928 # (we deliberately don't call render on self converters)
929 stock_self = self_converter('self', f)
930 template_dict['self_name'] = stock_self.name
931 template_dict['self_type'] = stock_self.type
932 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
933 if f.self_converter.type != stock_self.type:
934 self_cast = '(' + f.self_converter.type + ')'
935 else:
936 self_cast = ''
937 data.impl_arguments.insert(0, self_cast + stock_self.name)
938
Larry Hastings31826802013-10-19 00:09:25 -0700939 f.return_converter.render(f, data)
940 template_dict['impl_return_type'] = f.return_converter.type
941
942 template_dict['declarations'] = "\n".join(data.declarations)
943 template_dict['initializers'] = "\n\n".join(data.initializers)
944 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
945 template_dict['format_units'] = ''.join(data.format_units)
946 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
947 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
948 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
949 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
950 template_dict['cleanup'] = "".join(data.cleanup)
951 template_dict['return_value'] = data.return_value
952
Larry Hastingsbebf7352014-01-17 17:47:17 -0800953 if has_option_groups:
Larry Hastings31826802013-10-19 00:09:25 -0700954 self.render_option_group_parsing(f, template_dict)
Larry Hastingsbebf7352014-01-17 17:47:17 -0800955
956 templates = self.output_templates(f)
957
958 for name, destination in clinic.field_destinations.items():
959 template = templates[name]
960 if has_option_groups:
961 template = linear_format(template,
962 option_group_parsing=template_dict['option_group_parsing'])
Larry Hastings31826802013-10-19 00:09:25 -0700963 template = linear_format(template,
Larry Hastingsbebf7352014-01-17 17:47:17 -0800964 declarations=template_dict['declarations'],
965 return_conversion=template_dict['return_conversion'],
966 initializers=template_dict['initializers'],
967 cleanup=template_dict['cleanup'],
968 )
Larry Hastings31826802013-10-19 00:09:25 -0700969
Larry Hastingsbebf7352014-01-17 17:47:17 -0800970 # Only generate the "exit:" label
971 # if we have any gotos
972 need_exit_label = "goto exit;" in template
973 template = linear_format(template,
974 exit_label="exit:" if need_exit_label else ''
975 )
Larry Hastings31826802013-10-19 00:09:25 -0700976
Larry Hastingsbebf7352014-01-17 17:47:17 -0800977 s = template.format_map(template_dict)
Larry Hastings31826802013-10-19 00:09:25 -0700978
Larry Hastingsbebf7352014-01-17 17:47:17 -0800979 if clinic.line_prefix:
980 s = indent_all_lines(s, clinic.line_prefix)
981 if clinic.line_suffix:
982 s = suffix_all_lines(s, clinic.line_suffix)
983
984 destination.append(s)
985
986 return clinic.get_destination('block').dump()
987
Larry Hastings31826802013-10-19 00:09:25 -0700988
989
990@contextlib.contextmanager
991def OverrideStdioWith(stdout):
992 saved_stdout = sys.stdout
993 sys.stdout = stdout
994 try:
995 yield
996 finally:
997 assert sys.stdout is stdout
998 sys.stdout = saved_stdout
999
1000
1001def create_regex(before, after):
1002 """Create an re object for matching marker lines."""
1003 pattern = r'^{}(\w+){}$'
1004 return re.compile(pattern.format(re.escape(before), re.escape(after)))
1005
1006
1007class Block:
1008 r"""
1009 Represents a single block of text embedded in
1010 another file. If dsl_name is None, the block represents
1011 verbatim text, raw original text from the file, in
1012 which case "input" will be the only non-false member.
1013 If dsl_name is not None, the block represents a Clinic
1014 block.
1015
1016 input is always str, with embedded \n characters.
1017 input represents the original text from the file;
1018 if it's a Clinic block, it is the original text with
1019 the body_prefix and redundant leading whitespace removed.
1020
1021 dsl_name is either str or None. If str, it's the text
1022 found on the start line of the block between the square
1023 brackets.
1024
1025 signatures is either list or None. If it's a list,
1026 it may only contain clinic.Module, clinic.Class, and
1027 clinic.Function objects. At the moment it should
1028 contain at most one of each.
1029
1030 output is either str or None. If str, it's the output
1031 from this block, with embedded '\n' characters.
1032
1033 indent is either str or None. It's the leading whitespace
1034 that was found on every line of input. (If body_prefix is
1035 not empty, this is the indent *after* removing the
1036 body_prefix.)
1037
1038 preindent is either str or None. It's the whitespace that
1039 was found in front of every line of input *before* the
1040 "body_prefix" (see the Language object). If body_prefix
1041 is empty, preindent must always be empty too.
1042
1043 To illustrate indent and preindent: Assume that '_'
1044 represents whitespace. If the block processed was in a
1045 Python file, and looked like this:
1046 ____#/*[python]
1047 ____#__for a in range(20):
1048 ____#____print(a)
1049 ____#[python]*/
1050 "preindent" would be "____" and "indent" would be "__".
1051
1052 """
1053 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
1054 assert isinstance(input, str)
1055 self.input = input
1056 self.dsl_name = dsl_name
1057 self.signatures = signatures or []
1058 self.output = output
1059 self.indent = indent
1060 self.preindent = preindent
1061
1062
1063class BlockParser:
1064 """
1065 Block-oriented parser for Argument Clinic.
1066 Iterator, yields Block objects.
1067 """
1068
1069 def __init__(self, input, language, *, verify=True):
1070 """
1071 "input" should be a str object
1072 with embedded \n characters.
1073
1074 "language" should be a Language object.
1075 """
1076 language.validate()
1077
1078 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
1079 self.block_start_line_number = self.line_number = 0
1080
1081 self.language = language
1082 before, _, after = language.start_line.partition('{dsl_name}')
1083 assert _ == '{dsl_name}'
1084 self.start_re = create_regex(before, after)
1085 self.verify = verify
1086 self.last_checksum_re = None
1087 self.last_dsl_name = None
1088 self.dsl_name = None
Larry Hastingsbebf7352014-01-17 17:47:17 -08001089 self.first_block = True
Larry Hastings31826802013-10-19 00:09:25 -07001090
1091 def __iter__(self):
1092 return self
1093
1094 def __next__(self):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001095 while True:
1096 if not self.input:
1097 raise StopIteration
Larry Hastings31826802013-10-19 00:09:25 -07001098
Larry Hastingsbebf7352014-01-17 17:47:17 -08001099 if self.dsl_name:
1100 return_value = self.parse_clinic_block(self.dsl_name)
1101 self.dsl_name = None
1102 self.first_block = False
1103 return return_value
1104 block = self.parse_verbatim_block()
1105 if self.first_block and not block.input:
1106 continue
1107 self.first_block = False
1108 return block
1109
Larry Hastings31826802013-10-19 00:09:25 -07001110
1111 def is_start_line(self, line):
1112 match = self.start_re.match(line.lstrip())
1113 return match.group(1) if match else None
1114
1115 def _line(self):
1116 self.line_number += 1
1117 return self.input.pop()
1118
1119 def parse_verbatim_block(self):
1120 add, output = text_accumulator()
1121 self.block_start_line_number = self.line_number
1122
1123 while self.input:
1124 line = self._line()
1125 dsl_name = self.is_start_line(line)
1126 if dsl_name:
1127 self.dsl_name = dsl_name
1128 break
1129 add(line)
1130
1131 return Block(output())
1132
1133 def parse_clinic_block(self, dsl_name):
1134 input_add, input_output = text_accumulator()
1135 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -08001136 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -07001137 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1138
Larry Hastings90261132014-01-07 12:21:08 -08001139 def is_stop_line(line):
1140 # make sure to recognize stop line even if it
1141 # doesn't end with EOL (it could be the very end of the file)
1142 if not line.startswith(stop_line):
1143 return False
1144 remainder = line[len(stop_line):]
1145 return (not remainder) or remainder.isspace()
1146
Larry Hastings31826802013-10-19 00:09:25 -07001147 # consume body of program
1148 while self.input:
1149 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -08001150 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -07001151 break
1152 if body_prefix:
1153 line = line.lstrip()
1154 assert line.startswith(body_prefix)
1155 line = line[len(body_prefix):]
1156 input_add(line)
1157
1158 # consume output and checksum line, if present.
1159 if self.last_dsl_name == dsl_name:
1160 checksum_re = self.last_checksum_re
1161 else:
1162 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
1163 assert _ == '{checksum}'
1164 checksum_re = create_regex(before, after)
1165 self.last_dsl_name = dsl_name
1166 self.last_checksum_re = checksum_re
1167
1168 # scan forward for checksum line
1169 output_add, output_output = text_accumulator()
1170 checksum = None
1171 while self.input:
1172 line = self._line()
1173 match = checksum_re.match(line.lstrip())
1174 checksum = match.group(1) if match else None
1175 if checksum:
1176 break
1177 output_add(line)
1178 if self.is_start_line(line):
1179 break
1180
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07001181 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -07001182 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -07001183 if self.verify:
1184 computed = compute_checksum(output)
1185 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001186 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
1187 "Suggested fix: remove all generated code including "
Larry Hastingsbebf7352014-01-17 17:47:17 -08001188 "the end marker,\n"
1189 "or use the '-f' option."
Antoine Pitroucc1d31e2014-01-14 20:52:01 +01001190 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -07001191 else:
1192 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -08001193 output_lines = output.splitlines(keepends=True)
1194 self.line_number -= len(output_lines)
1195 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -07001196 output = None
1197
1198 return Block(input_output(), dsl_name, output=output)
1199
1200
1201class BlockPrinter:
1202
1203 def __init__(self, language, f=None):
1204 self.language = language
1205 self.f = f or io.StringIO()
1206
1207 def print_block(self, block):
1208 input = block.input
1209 output = block.output
1210 dsl_name = block.dsl_name
1211 write = self.f.write
1212
Larry Hastings31826802013-10-19 00:09:25 -07001213 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1214
1215 if not dsl_name:
1216 write(input)
1217 return
1218
1219 write(self.language.start_line.format(dsl_name=dsl_name))
1220 write("\n")
1221
1222 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1223 if not body_prefix:
1224 write(input)
1225 else:
1226 for line in input.split('\n'):
1227 write(body_prefix)
1228 write(line)
1229 write("\n")
1230
1231 write(self.language.stop_line.format(dsl_name=dsl_name))
1232 write("\n")
1233
Larry Hastingsbebf7352014-01-17 17:47:17 -08001234 output = ''.join(block.output)
Larry Hastings31826802013-10-19 00:09:25 -07001235 if output:
Larry Hastings31826802013-10-19 00:09:25 -07001236 if not output.endswith('\n'):
Larry Hastingsbebf7352014-01-17 17:47:17 -08001237 output += '\n'
1238 write(output)
Larry Hastings31826802013-10-19 00:09:25 -07001239
1240 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
1241 write("\n")
1242
Larry Hastingsbebf7352014-01-17 17:47:17 -08001243 def write(self, text):
1244 self.f.write(text)
1245
1246
1247class Destination:
1248 def __init__(self, name, type, clinic, *args):
1249 self.name = name
1250 self.type = type
1251 self.clinic = clinic
1252 valid_types = ('buffer', 'file', 'suppress', 'two-pass')
1253 if type not in valid_types:
1254 fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types))
1255 extra_arguments = 1 if type == "file" else 0
1256 if len(args) < extra_arguments:
1257 fail("Not enough arguments for destination " + name + " new " + type)
1258 if len(args) > extra_arguments:
1259 fail("Too many arguments for destination " + name + " new " + type)
1260 if type =='file':
1261 d = {}
1262 d['filename'] = filename = clinic.filename
1263 d['basename'], d['extension'] = os.path.splitext(filename)
1264 self.filename = args[0].format_map(d)
1265 if type == 'two-pass':
1266 self.id = None
1267
1268 self.text, self.append, self._dump = _text_accumulator()
1269
1270 def __repr__(self):
1271 if self.type == 'file':
1272 file_repr = " " + repr(self.filename)
1273 else:
1274 file_repr = ''
1275 return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
1276
1277 def clear(self):
1278 if self.type != 'buffer':
1279 fail("Can't clear destination" + self.name + " , it's not of type buffer")
1280 self.text.clear()
1281
1282 def dump(self):
1283 if self.type == 'two-pass':
1284 if self.id is None:
1285 self.id = str(uuid.uuid4())
1286 return self.id
1287 fail("You can only dump a two-pass buffer exactly once!")
1288 return self._dump()
1289
Larry Hastings31826802013-10-19 00:09:25 -07001290
1291# maps strings to Language objects.
1292# "languages" maps the name of the language ("C", "Python").
1293# "extensions" maps the file extension ("c", "py").
1294languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001295extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1296extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001297
1298
1299# maps strings to callables.
1300# these callables must be of the form:
1301# def foo(name, default, *, ...)
1302# The callable may have any number of keyword-only parameters.
1303# The callable must return a CConverter object.
1304# The callable should not call builtins.print.
1305converters = {}
1306
1307# maps strings to callables.
1308# these callables follow the same rules as those for "converters" above.
1309# note however that they will never be called with keyword-only parameters.
1310legacy_converters = {}
1311
1312
1313# maps strings to callables.
1314# these callables must be of the form:
1315# def foo(*, ...)
1316# The callable may have any number of keyword-only parameters.
1317# The callable must return a CConverter object.
1318# The callable should not call builtins.print.
1319return_converters = {}
1320
1321class Clinic:
Larry Hastingsbebf7352014-01-17 17:47:17 -08001322
1323 presets_text = """
1324preset original
1325everything block
1326docstring_prototype suppress
1327parser_prototype suppress
1328
1329preset file
1330everything file
1331docstring_prototype suppress
1332parser_prototype suppress
1333impl_definition block
1334
1335preset buffer
1336everything buffer
1337docstring_prototype suppress
1338impl_prototype suppress
1339parser_prototype suppress
1340impl_definition block
1341
1342preset partial-buffer
1343everything buffer
1344docstring_prototype block
1345impl_prototype suppress
1346methoddef_define block
1347parser_prototype block
1348impl_definition block
1349
1350preset two-pass
1351everything buffer
1352docstring_prototype two-pass
1353impl_prototype suppress
1354methoddef_define two-pass
1355parser_prototype two-pass
1356impl_definition block
1357
1358"""
1359
Larry Hastings31826802013-10-19 00:09:25 -07001360 def __init__(self, language, printer=None, *, verify=True, filename=None):
1361 # maps strings to Parser objects.
1362 # (instantiated from the "parsers" global.)
1363 self.parsers = {}
1364 self.language = language
Larry Hastingsbebf7352014-01-17 17:47:17 -08001365 if printer:
1366 fail("Custom printers are broken right now")
Larry Hastings31826802013-10-19 00:09:25 -07001367 self.printer = printer or BlockPrinter(language)
1368 self.verify = verify
1369 self.filename = filename
1370 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001371 self.classes = collections.OrderedDict()
Larry Hastings2a727912014-01-16 11:32:01 -08001372 self.functions = []
Larry Hastings31826802013-10-19 00:09:25 -07001373
Larry Hastingsbebf7352014-01-17 17:47:17 -08001374 self.line_prefix = self.line_suffix = ''
1375
1376 self.destinations = {}
1377 self.add_destination("block", "buffer")
1378 self.add_destination("suppress", "suppress")
1379 self.add_destination("buffer", "buffer")
1380 self.add_destination("two-pass", "two-pass")
1381 if filename:
1382 self.add_destination("file", "file", "{basename}.clinic{extension}")
1383
1384 d = self.destinations.get
1385 self.field_destinations = collections.OrderedDict((
1386 ('docstring_prototype', d('suppress')),
1387 ('docstring_definition', d('block')),
1388 ('methoddef_define', d('block')),
1389 ('impl_prototype', d('block')),
1390 ('parser_prototype', d('suppress')),
1391 ('parser_definition', d('block')),
1392 ('impl_definition', d('block')),
1393 ))
1394
1395 self.field_destinations_stack = []
1396
1397 self.presets = {}
1398 preset = None
1399 for line in self.presets_text.strip().split('\n'):
1400 line = line.strip()
1401 if not line:
1402 continue
1403 name, value = line.split()
1404 if name == 'preset':
1405 self.presets[value] = preset = collections.OrderedDict()
1406 continue
1407
1408 destination = self.get_destination(value)
1409
1410 if name == 'everything':
1411 for name in self.field_destinations:
1412 preset[name] = destination
1413 continue
1414
1415 assert name in self.field_destinations
1416 preset[name] = destination
1417
Larry Hastings31826802013-10-19 00:09:25 -07001418 global clinic
1419 clinic = self
1420
Larry Hastingsbebf7352014-01-17 17:47:17 -08001421 def get_destination(self, name, default=unspecified):
1422 d = self.destinations.get(name)
1423 if not d:
1424 if default is not unspecified:
1425 return default
1426 fail("Destination does not exist: " + repr(name))
1427 return d
1428
1429 def add_destination(self, name, type, *args):
1430 if name in self.destinations:
1431 fail("Destination already exists: " + repr(name))
1432 self.destinations[name] = Destination(name, type, self, *args)
1433
Larry Hastings31826802013-10-19 00:09:25 -07001434 def parse(self, input):
1435 printer = self.printer
1436 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1437 for block in self.block_parser:
1438 dsl_name = block.dsl_name
1439 if dsl_name:
1440 if dsl_name not in self.parsers:
1441 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1442 self.parsers[dsl_name] = parsers[dsl_name](self)
1443 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001444 try:
1445 parser.parse(block)
1446 except Exception:
1447 fail('Exception raised during parsing:\n' +
1448 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001449 printer.print_block(block)
Larry Hastingsbebf7352014-01-17 17:47:17 -08001450
1451 second_pass_replacements = {}
1452
1453 for name, destination in self.destinations.items():
1454 if destination.type == 'suppress':
1455 continue
1456 output = destination._dump()
1457
1458 if destination.type == 'two-pass':
1459 if destination.id:
1460 second_pass_replacements[destination.id] = output
1461 elif output:
1462 fail("Two-pass buffer " + repr(name) + " not empty at end of file!")
1463 continue
1464
1465 if output:
1466
1467 block = Block("", dsl_name="clinic", output=output)
1468
1469 if destination.type == 'buffer':
1470 block.input = "dump " + name + "\n"
1471 warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
1472 printer.write("\n")
1473 printer.print_block(block)
1474 continue
1475
1476 if destination.type == 'file':
1477 try:
1478 with open(destination.filename, "rt") as f:
1479 parser_2 = BlockParser(f.read(), language=self.language)
1480 blocks = list(parser_2)
1481 if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'):
1482 fail("Modified destination file " + repr(destination.filename) + ", not overwriting!")
1483 except FileNotFoundError:
1484 pass
1485
1486 block.input = 'preserve\n'
1487 printer_2 = BlockPrinter(self.language)
1488 printer_2.print_block(block)
1489 with open(destination.filename, "wt") as f:
1490 f.write(printer_2.f.getvalue())
1491 continue
1492 text = printer.f.getvalue()
1493
1494 if second_pass_replacements:
1495 printer_2 = BlockPrinter(self.language)
1496 parser_2 = BlockParser(text, self.language)
1497 changed = False
1498 for block in parser_2:
1499 if block.dsl_name:
1500 for id, replacement in second_pass_replacements.items():
1501 if id in block.output:
1502 changed = True
1503 block.output = block.output.replace(id, replacement)
1504 printer_2.print_block(block)
1505 if changed:
1506 text = printer_2.f.getvalue()
1507
1508 return text
1509
Larry Hastings31826802013-10-19 00:09:25 -07001510
1511 def _module_and_class(self, fields):
1512 """
1513 fields should be an iterable of field names.
1514 returns a tuple of (module, class).
1515 the module object could actually be self (a clinic object).
1516 this function is only ever used to find the parent of where
1517 a new class/module should go.
1518 """
1519 in_classes = False
1520 parent = module = self
1521 cls = None
1522 so_far = []
1523
1524 for field in fields:
1525 so_far.append(field)
1526 if not in_classes:
1527 child = parent.modules.get(field)
1528 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001529 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001530 continue
1531 in_classes = True
1532 if not hasattr(parent, 'classes'):
1533 return module, cls
1534 child = parent.classes.get(field)
1535 if not child:
1536 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1537 cls = parent = child
1538
1539 return module, cls
1540
1541
1542def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1543 extension = os.path.splitext(filename)[1][1:]
1544 if not extension:
1545 fail("Can't extract file type for file " + repr(filename))
1546
1547 try:
1548 language = extensions[extension]()
1549 except KeyError:
1550 fail("Can't identify file type for file " + repr(filename))
1551
1552 clinic = Clinic(language, verify=verify, filename=filename)
1553
1554 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001555 raw = f.read()
1556
1557 cooked = clinic.parse(raw)
1558 if cooked == raw:
1559 return
Larry Hastings31826802013-10-19 00:09:25 -07001560
1561 directory = os.path.dirname(filename) or '.'
1562
1563 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001564 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001565 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1566 with open(tmpfilename, "wb") as f:
1567 f.write(bytes)
1568 os.replace(tmpfilename, output or filename)
1569
1570
1571def compute_checksum(input):
1572 input = input or ''
1573 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1574
1575
1576
1577
1578class PythonParser:
1579 def __init__(self, clinic):
1580 pass
1581
1582 def parse(self, block):
1583 s = io.StringIO()
1584 with OverrideStdioWith(s):
1585 exec(block.input)
1586 block.output = s.getvalue()
1587
1588
1589class Module:
1590 def __init__(self, name, module=None):
1591 self.name = name
1592 self.module = self.parent = module
1593
1594 self.modules = collections.OrderedDict()
1595 self.classes = collections.OrderedDict()
1596 self.functions = []
1597
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001598 def __repr__(self):
1599 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1600
Larry Hastings31826802013-10-19 00:09:25 -07001601class Class:
1602 def __init__(self, name, module=None, cls=None):
1603 self.name = name
1604 self.module = module
1605 self.cls = cls
1606 self.parent = cls or module
1607
1608 self.classes = collections.OrderedDict()
1609 self.functions = []
1610
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001611 def __repr__(self):
1612 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1613
Larry Hastings8666e652014-01-12 14:12:59 -08001614unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001615
Larry Hastings8666e652014-01-12 14:12:59 -08001616__abs__
1617__add__
1618__and__
1619__bytes__
1620__call__
1621__complex__
1622__delitem__
1623__divmod__
1624__eq__
1625__float__
1626__floordiv__
1627__ge__
1628__getattr__
1629__getattribute__
1630__getitem__
1631__gt__
1632__hash__
1633__iadd__
1634__iand__
1635__idivmod__
1636__ifloordiv__
1637__ilshift__
1638__imod__
1639__imul__
1640__index__
1641__int__
1642__invert__
1643__ior__
1644__ipow__
1645__irshift__
1646__isub__
1647__iter__
1648__itruediv__
1649__ixor__
1650__le__
1651__len__
1652__lshift__
1653__lt__
1654__mod__
1655__mul__
1656__neg__
1657__new__
1658__next__
1659__or__
1660__pos__
1661__pow__
1662__radd__
1663__rand__
1664__rdivmod__
1665__repr__
1666__rfloordiv__
1667__rlshift__
1668__rmod__
1669__rmul__
1670__ror__
1671__round__
1672__rpow__
1673__rrshift__
1674__rshift__
1675__rsub__
1676__rtruediv__
1677__rxor__
1678__setattr__
1679__setitem__
1680__str__
1681__sub__
1682__truediv__
1683__xor__
1684
1685""".strip().split())
1686
1687
1688INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6)
Larry Hastings31826802013-10-19 00:09:25 -07001689
1690class Function:
1691 """
1692 Mutable duck type for inspect.Function.
1693
1694 docstring - a str containing
1695 * embedded line breaks
1696 * text outdented to the left margin
1697 * no trailing whitespace.
1698 It will always be true that
1699 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1700 """
1701
1702 def __init__(self, parameters=None, *, name,
1703 module, cls=None, c_basename=None,
1704 full_name=None,
1705 return_converter, return_annotation=_empty,
1706 docstring=None, kind=CALLABLE, coexist=False):
1707 self.parameters = parameters or collections.OrderedDict()
1708 self.return_annotation = return_annotation
1709 self.name = name
1710 self.full_name = full_name
1711 self.module = module
1712 self.cls = cls
1713 self.parent = cls or module
1714 self.c_basename = c_basename
1715 self.return_converter = return_converter
1716 self.docstring = docstring or ''
1717 self.kind = kind
1718 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001719 self.self_converter = None
1720
1721 @property
1722 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001723 if self.kind in (METHOD_INIT, METHOD_NEW):
1724 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001725 flags = []
1726 if self.kind == CLASS_METHOD:
1727 flags.append('METH_CLASS')
1728 elif self.kind == STATIC_METHOD:
1729 flags.append('METH_STATIC')
1730 else:
1731 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1732 if self.coexist:
1733 flags.append('METH_COEXIST')
1734 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001735
1736 def __repr__(self):
1737 return '<clinic.Function ' + self.name + '>'
1738
1739
1740class Parameter:
1741 """
1742 Mutable duck type of inspect.Parameter.
1743 """
1744
1745 def __init__(self, name, kind, *, default=_empty,
1746 function, converter, annotation=_empty,
1747 docstring=None, group=0):
1748 self.name = name
1749 self.kind = kind
1750 self.default = default
1751 self.function = function
1752 self.converter = converter
1753 self.annotation = annotation
1754 self.docstring = docstring or ''
1755 self.group = group
1756
1757 def __repr__(self):
1758 return '<clinic.Parameter ' + self.name + '>'
1759
1760 def is_keyword_only(self):
1761 return self.kind == inspect.Parameter.KEYWORD_ONLY
1762
Larry Hastings31826802013-10-19 00:09:25 -07001763
Larry Hastings31826802013-10-19 00:09:25 -07001764
1765def add_c_converter(f, name=None):
1766 if not name:
1767 name = f.__name__
1768 if not name.endswith('_converter'):
1769 return f
1770 name = name[:-len('_converter')]
1771 converters[name] = f
1772 return f
1773
1774def add_default_legacy_c_converter(cls):
1775 # automatically add converter for default format unit
1776 # (but without stomping on the existing one if it's already
1777 # set, in case you subclass)
1778 if ((cls.format_unit != 'O&') and
1779 (cls.format_unit not in legacy_converters)):
1780 legacy_converters[cls.format_unit] = cls
1781 return cls
1782
1783def add_legacy_c_converter(format_unit, **kwargs):
1784 """
1785 Adds a legacy converter.
1786 """
1787 def closure(f):
1788 if not kwargs:
1789 added_f = f
1790 else:
1791 added_f = functools.partial(f, **kwargs)
1792 legacy_converters[format_unit] = added_f
1793 return f
1794 return closure
1795
1796class CConverterAutoRegister(type):
1797 def __init__(cls, name, bases, classdict):
1798 add_c_converter(cls)
1799 add_default_legacy_c_converter(cls)
1800
1801class CConverter(metaclass=CConverterAutoRegister):
1802 """
1803 For the init function, self, name, function, and default
1804 must be keyword-or-positional parameters. All other
Larry Hastings2a727912014-01-16 11:32:01 -08001805 parameters must be keyword-only.
Larry Hastings31826802013-10-19 00:09:25 -07001806 """
1807
Larry Hastings78cf85c2014-01-04 12:44:57 -08001808 # The C type to use for this variable.
1809 # 'type' should be a Python string specifying the type, e.g. "int".
1810 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001811 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001812
1813 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001814 # Or the magic value "unspecified" if there is no default.
Larry Hastings2a727912014-01-16 11:32:01 -08001815 # Or the magic value "unknown" if this value is a cannot be evaluated
1816 # at Argument-Clinic-preprocessing time (but is presumed to be valid
1817 # at runtime).
Larry Hastings31826802013-10-19 00:09:25 -07001818 default = unspecified
1819
Larry Hastings4a55fc52014-01-12 11:09:57 -08001820 # If not None, default must be isinstance() of this type.
1821 # (You can also specify a tuple of types.)
1822 default_type = None
1823
Larry Hastings31826802013-10-19 00:09:25 -07001824 # "default" converted into a C value, as a string.
1825 # Or None if there is no default.
1826 c_default = None
1827
Larry Hastings2a727912014-01-16 11:32:01 -08001828 # "default" converted into a Python value, as a string.
1829 # Or None if there is no default.
1830 py_default = None
1831
Larry Hastingsabc716b2013-11-20 09:13:52 -08001832 # The default value used to initialize the C variable when
1833 # there is no default, but not specifying a default may
1834 # result in an "uninitialized variable" warning. This can
1835 # easily happen when using option groups--although
1836 # properly-written code won't actually use the variable,
1837 # the variable does get passed in to the _impl. (Ah, if
1838 # only dataflow analysis could inline the static function!)
1839 #
1840 # This value is specified as a string.
1841 # Every non-abstract subclass should supply a valid value.
1842 c_ignored_default = 'NULL'
1843
Larry Hastings31826802013-10-19 00:09:25 -07001844 # The C converter *function* to be used, if any.
1845 # (If this is not None, format_unit must be 'O&'.)
1846 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001847
Larry Hastings78cf85c2014-01-04 12:44:57 -08001848 # Should Argument Clinic add a '&' before the name of
1849 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001850 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001851
1852 # Should Argument Clinic add a '&' before the name of
1853 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001854 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001855
1856 #############################################################
1857 #############################################################
1858 ## You shouldn't need to read anything below this point to ##
1859 ## write your own converter functions. ##
1860 #############################################################
1861 #############################################################
1862
1863 # The "format unit" to specify for this variable when
1864 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1865 # Custom converters should always use the default value of 'O&'.
1866 format_unit = 'O&'
1867
1868 # What encoding do we want for this variable? Only used
1869 # by format units starting with 'e'.
1870 encoding = None
1871
Larry Hastings77561cc2014-01-07 12:13:13 -08001872 # Should this object be required to be a subclass of a specific type?
1873 # If not None, should be a string representing a pointer to a
1874 # PyTypeObject (e.g. "&PyUnicode_Type").
1875 # Only used by the 'O!' format unit (and the "object" converter).
1876 subclass_of = None
1877
Larry Hastings78cf85c2014-01-04 12:44:57 -08001878 # Do we want an adjacent '_length' variable for this variable?
1879 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001880 length = False
1881
Larry Hastings2a727912014-01-16 11:32:01 -08001882 def __init__(self, name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
Larry Hastings31826802013-10-19 00:09:25 -07001883 self.function = function
1884 self.name = name
1885
1886 if default is not unspecified:
Larry Hastings2a727912014-01-16 11:32:01 -08001887 if self.default_type and not isinstance(default, (self.default_type, Unknown)):
Larry Hastings4a55fc52014-01-12 11:09:57 -08001888 if isinstance(self.default_type, type):
1889 types_str = self.default_type.__name__
1890 else:
1891 types_str = ', '.join((cls.__name__ for cls in self.default_type))
1892 fail("{}: default value {!r} for field {} is not of type {}".format(
1893 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07001894 self.default = default
Larry Hastings2a727912014-01-16 11:32:01 -08001895
Larry Hastingsb4705752014-01-18 21:54:15 -08001896 if c_default:
1897 self.c_default = c_default
1898 if py_default:
1899 self.py_default = py_default
Larry Hastings2a727912014-01-16 11:32:01 -08001900
Larry Hastings31826802013-10-19 00:09:25 -07001901 if annotation != unspecified:
1902 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings31826802013-10-19 00:09:25 -07001903 self.converter_init(**kwargs)
1904
1905 def converter_init(self):
1906 pass
1907
1908 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08001909 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07001910
1911 def render(self, parameter, data):
1912 """
1913 parameter is a clinic.Parameter instance.
1914 data is a CRenderData instance.
1915 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001916 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08001917 original_name = self.name
1918 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001919
1920 # declarations
1921 d = self.declaration()
1922 data.declarations.append(d)
1923
1924 # initializers
1925 initializers = self.initialize()
1926 if initializers:
1927 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1928
1929 # impl_arguments
1930 s = ("&" if self.impl_by_reference else "") + name
1931 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001932 if self.length:
1933 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001934
1935 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08001936 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001937
1938 # format_units
1939 if self.is_optional() and '|' not in data.format_units:
1940 data.format_units.append('|')
1941 if parameter.is_keyword_only() and '$' not in data.format_units:
1942 data.format_units.append('$')
1943 data.format_units.append(self.format_unit)
1944
1945 # parse_arguments
1946 self.parse_argument(data.parse_arguments)
1947
1948 # impl_parameters
1949 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001950 if self.length:
1951 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001952
1953 # cleanup
1954 cleanup = self.cleanup()
1955 if cleanup:
1956 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1957
Larry Hastingsebdcb502013-11-23 14:54:00 -08001958 def length_name(self):
1959 """Computes the name of the associated "length" variable."""
1960 if not self.length:
1961 return None
1962 return ensure_legal_c_identifier(self.name) + "_length"
1963
Larry Hastings31826802013-10-19 00:09:25 -07001964 # Why is this one broken out separately?
1965 # For "positional-only" function parsing,
1966 # which generates a bunch of PyArg_ParseTuple calls.
1967 def parse_argument(self, list):
1968 assert not (self.converter and self.encoding)
1969 if self.format_unit == 'O&':
1970 assert self.converter
1971 list.append(self.converter)
1972
1973 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08001974 list.append(c_repr(self.encoding))
1975 elif self.subclass_of:
1976 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07001977
Larry Hastingsebdcb502013-11-23 14:54:00 -08001978 legal_name = ensure_legal_c_identifier(self.name)
1979 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001980 list.append(s)
1981
Larry Hastingsebdcb502013-11-23 14:54:00 -08001982 if self.length:
1983 list.append("&" + self.length_name())
1984
Larry Hastings31826802013-10-19 00:09:25 -07001985 #
1986 # All the functions after here are intended as extension points.
1987 #
1988
1989 def simple_declaration(self, by_reference=False):
1990 """
1991 Computes the basic declaration of the variable.
1992 Used in computing the prototype declaration and the
1993 variable declaration.
1994 """
1995 prototype = [self.type]
1996 if by_reference or not self.type.endswith('*'):
1997 prototype.append(" ")
1998 if by_reference:
1999 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002000 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07002001 return "".join(prototype)
2002
2003 def declaration(self):
2004 """
2005 The C statement to declare this variable.
2006 """
2007 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002008 default = self.c_default
2009 if not default and self.parameter.group:
2010 default = self.c_ignored_default
2011 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002012 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002013 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002014 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002015 if self.length:
2016 declaration.append('\nPy_ssize_clean_t ')
2017 declaration.append(self.length_name())
2018 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08002019 s = "".join(declaration)
2020 # double up curly-braces, this string will be used
2021 # as part of a format_map() template later
2022 s = s.replace("{", "{{")
2023 s = s.replace("}", "}}")
2024 return s
Larry Hastings31826802013-10-19 00:09:25 -07002025
2026 def initialize(self):
2027 """
2028 The C statements required to set up this variable before parsing.
2029 Returns a string containing this code indented at column 0.
2030 If no initialization is necessary, returns an empty string.
2031 """
2032 return ""
2033
2034 def cleanup(self):
2035 """
2036 The C statements required to clean up after this variable.
2037 Returns a string containing this code indented at column 0.
2038 If no cleanup is necessary, returns an empty string.
2039 """
2040 return ""
2041
2042
2043class bool_converter(CConverter):
2044 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002045 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002046 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002047 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002048
2049 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002050 if self.default is not unspecified:
2051 self.default = bool(self.default)
2052 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002053
2054class char_converter(CConverter):
2055 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002056 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07002057 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002058 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002059
Larry Hastings4a55fc52014-01-12 11:09:57 -08002060 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002061 if isinstance(self.default, str) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002062 fail("char_converter: illegal default value " + repr(self.default))
2063
2064
Larry Hastings31826802013-10-19 00:09:25 -07002065@add_legacy_c_converter('B', bitwise=True)
2066class byte_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002067 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002068 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002069 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002070 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002071
2072 def converter_init(self, *, bitwise=False):
2073 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002074 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002075
2076class short_converter(CConverter):
2077 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002078 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002079 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002080 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002081
2082class unsigned_short_converter(CConverter):
2083 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002084 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002085 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002086 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002087
2088 def converter_init(self, *, bitwise=False):
2089 if not bitwise:
2090 fail("Unsigned shorts must be bitwise (for now).")
2091
Larry Hastingsebdcb502013-11-23 14:54:00 -08002092@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07002093class int_converter(CConverter):
2094 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002095 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002096 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002097 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002098
Larry Hastingsebdcb502013-11-23 14:54:00 -08002099 def converter_init(self, *, types='int'):
2100 if types == 'str':
2101 self.format_unit = 'C'
2102 elif types != 'int':
2103 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07002104
2105class unsigned_int_converter(CConverter):
2106 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002107 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002108 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002109 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002110
2111 def converter_init(self, *, bitwise=False):
2112 if not bitwise:
2113 fail("Unsigned ints must be bitwise (for now).")
2114
2115class long_converter(CConverter):
2116 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002117 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002118 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002119 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002120
2121class unsigned_long_converter(CConverter):
2122 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002123 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002124 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002125 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002126
2127 def converter_init(self, *, bitwise=False):
2128 if not bitwise:
2129 fail("Unsigned longs must be bitwise (for now).")
2130
2131class PY_LONG_LONG_converter(CConverter):
2132 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002133 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002134 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002135 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002136
2137class unsigned_PY_LONG_LONG_converter(CConverter):
2138 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002139 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002140 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002141 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002142
2143 def converter_init(self, *, bitwise=False):
2144 if not bitwise:
2145 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
2146
2147class Py_ssize_t_converter(CConverter):
2148 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002149 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002150 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002151 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002152
2153
2154class float_converter(CConverter):
2155 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002156 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002157 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002158 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002159
2160class double_converter(CConverter):
2161 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002162 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002163 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002164 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002165
2166
2167class Py_complex_converter(CConverter):
2168 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002169 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002170 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002171 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002172
2173
2174class object_converter(CConverter):
2175 type = 'PyObject *'
2176 format_unit = 'O'
2177
Larry Hastings4a55fc52014-01-12 11:09:57 -08002178 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2179 if converter:
2180 if subclass_of:
2181 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2182 self.format_unit = 'O&'
2183 self.converter = converter
2184 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002185 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002186 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002187
Larry Hastings77561cc2014-01-07 12:13:13 -08002188 if type is not None:
2189 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002190
2191
Larry Hastingsebdcb502013-11-23 14:54:00 -08002192@add_legacy_c_converter('s#', length=True)
Larry Hastings2a727912014-01-16 11:32:01 -08002193@add_legacy_c_converter('y', types="bytes")
2194@add_legacy_c_converter('y#', types="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002195@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002196@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002197class str_converter(CConverter):
2198 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002199 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002200 format_unit = 's'
2201
Larry Hastingsebdcb502013-11-23 14:54:00 -08002202 def converter_init(self, *, encoding=None, types="str",
2203 length=False, nullable=False, zeroes=False):
2204
2205 types = set(types.strip().split())
2206 bytes_type = set(("bytes",))
2207 str_type = set(("str",))
2208 all_3_type = set(("bytearray",)) | bytes_type | str_type
2209 is_bytes = types == bytes_type
2210 is_str = types == str_type
2211 is_all_3 = types == all_3_type
2212
2213 self.length = bool(length)
2214 format_unit = None
2215
2216 if encoding:
2217 self.encoding = encoding
2218
2219 if is_str and not (length or zeroes or nullable):
2220 format_unit = 'es'
2221 elif is_all_3 and not (length or zeroes or nullable):
2222 format_unit = 'et'
2223 elif is_str and length and zeroes and not nullable:
2224 format_unit = 'es#'
2225 elif is_all_3 and length and not (nullable or zeroes):
2226 format_unit = 'et#'
2227
2228 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08002229 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002230 # TODO set pointer to NULL
2231 # TODO add cleanup for buffer
2232 pass
2233
2234 else:
2235 if zeroes:
2236 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
2237
2238 if is_bytes and not (nullable or length):
2239 format_unit = 'y'
2240 elif is_bytes and length and not nullable:
2241 format_unit = 'y#'
2242 elif is_str and not (nullable or length):
2243 format_unit = 's'
2244 elif is_str and length and not nullable:
2245 format_unit = 's#'
2246 elif is_str and nullable and not length:
2247 format_unit = 'z'
2248 elif is_str and nullable and length:
2249 format_unit = 'z#'
2250
2251 if not format_unit:
2252 fail("str_converter: illegal combination of arguments")
2253 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002254
2255
2256class PyBytesObject_converter(CConverter):
2257 type = 'PyBytesObject *'
2258 format_unit = 'S'
2259
2260class PyByteArrayObject_converter(CConverter):
2261 type = 'PyByteArrayObject *'
2262 format_unit = 'Y'
2263
2264class unicode_converter(CConverter):
2265 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002266 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002267 format_unit = 'U'
2268
Larry Hastingsebdcb502013-11-23 14:54:00 -08002269@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002270@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002271@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002272class Py_UNICODE_converter(CConverter):
2273 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002274 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002275 format_unit = 'u'
2276
Larry Hastingsebdcb502013-11-23 14:54:00 -08002277 def converter_init(self, *, nullable=False, length=False):
2278 format_unit = 'Z' if nullable else 'u'
2279 if length:
2280 format_unit += '#'
2281 self.length = True
2282 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002283
Larry Hastingsebdcb502013-11-23 14:54:00 -08002284#
2285# We define three string conventions for buffer types in the 'types' argument:
2286# 'buffer' : any object supporting the buffer interface
2287# 'rwbuffer': any object supporting the buffer interface, but must be writeable
2288# 'robuffer': any object supporting the buffer interface, but must not be writeable
2289#
2290@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
2291@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
2292@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07002293class Py_buffer_converter(CConverter):
2294 type = 'Py_buffer'
2295 format_unit = 'y*'
2296 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002297 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002298
Larry Hastingsebdcb502013-11-23 14:54:00 -08002299 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002300 if self.default not in (unspecified, None):
2301 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08002302 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002303 types = set(types.strip().split())
2304 bytes_type = set(('bytes',))
2305 bytearray_type = set(('bytearray',))
2306 buffer_type = set(('buffer',))
2307 rwbuffer_type = set(('rwbuffer',))
2308 robuffer_type = set(('robuffer',))
2309 str_type = set(('str',))
2310 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
2311
2312 format_unit = None
2313 if types == (str_type | bytes_bytearray_buffer_type):
2314 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07002315 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002316 if nullable:
2317 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
2318 elif types == (bytes_bytearray_buffer_type):
2319 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002320 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002321 format_unit = 'w*'
2322 if not format_unit:
2323 fail("Py_buffer_converter: illegal combination of arguments")
2324
2325 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002326
2327 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002328 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002329 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002330
2331
2332class self_converter(CConverter):
2333 """
2334 A special-case converter:
2335 this is the default converter used for "self".
2336 """
2337 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08002338 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002339 f = self.function
Larry Hastings8666e652014-01-12 14:12:59 -08002340 if f.kind in (CALLABLE, METHOD_INIT):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002341 if f.cls:
2342 self.name = "self"
2343 else:
2344 self.name = "module"
2345 self.type = "PyModuleDef *"
2346 elif f.kind == STATIC_METHOD:
2347 self.name = "null"
2348 self.type = "void *"
2349 elif f.kind == CLASS_METHOD:
2350 self.name = "cls"
2351 self.type = "PyTypeObject *"
Larry Hastings8666e652014-01-12 14:12:59 -08002352 elif f.kind == METHOD_NEW:
2353 self.name = "type"
2354 self.type = "PyTypeObject *"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002355
Larry Hastings78cf85c2014-01-04 12:44:57 -08002356 if type:
2357 self.type = type
2358
Larry Hastingsebdcb502013-11-23 14:54:00 -08002359 def render(self, parameter, data):
2360 fail("render() should never be called on self_converter instances")
2361
Larry Hastings31826802013-10-19 00:09:25 -07002362
2363
2364def add_c_return_converter(f, name=None):
2365 if not name:
2366 name = f.__name__
2367 if not name.endswith('_return_converter'):
2368 return f
2369 name = name[:-len('_return_converter')]
2370 return_converters[name] = f
2371 return f
2372
2373
2374class CReturnConverterAutoRegister(type):
2375 def __init__(cls, name, bases, classdict):
2376 add_c_return_converter(cls)
2377
2378class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2379
Larry Hastings78cf85c2014-01-04 12:44:57 -08002380 # The C type to use for this variable.
2381 # 'type' should be a Python string specifying the type, e.g. "int".
2382 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002383 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002384
2385 # The Python default value for this parameter, as a Python value.
2386 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002387 default = None
2388
Larry Hastings2a727912014-01-16 11:32:01 -08002389 def __init__(self, *, py_default=None, **kwargs):
2390 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002391 try:
2392 self.return_converter_init(**kwargs)
2393 except TypeError as e:
2394 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2395 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2396
2397 def return_converter_init(self):
2398 pass
2399
2400 def declare(self, data, name="_return_value"):
2401 line = []
2402 add = line.append
2403 add(self.type)
2404 if not self.type.endswith('*'):
2405 add(' ')
2406 add(name + ';')
2407 data.declarations.append(''.join(line))
2408 data.return_value = name
2409
2410 def err_occurred_if(self, expr, data):
2411 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2412
2413 def err_occurred_if_null_pointer(self, variable, data):
2414 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2415
2416 def render(self, function, data):
2417 """
2418 function is a clinic.Function instance.
2419 data is a CRenderData instance.
2420 """
2421 pass
2422
2423add_c_return_converter(CReturnConverter, 'object')
2424
Larry Hastings78cf85c2014-01-04 12:44:57 -08002425class NoneType_return_converter(CReturnConverter):
2426 def render(self, function, data):
2427 self.declare(data)
2428 data.return_conversion.append('''
2429if (_return_value != Py_None)
2430 goto exit;
2431return_value = Py_None;
2432Py_INCREF(Py_None);
2433'''.strip())
2434
Larry Hastings4a55fc52014-01-12 11:09:57 -08002435class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002436 type = 'int'
2437
2438 def render(self, function, data):
2439 self.declare(data)
2440 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002441 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002442
2443class long_return_converter(CReturnConverter):
2444 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002445 conversion_fn = 'PyLong_FromLong'
2446 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002447
2448 def render(self, function, data):
2449 self.declare(data)
2450 self.err_occurred_if("_return_value == -1", data)
2451 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002452 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002453
Larry Hastings4a55fc52014-01-12 11:09:57 -08002454class int_return_converter(long_return_converter):
2455 type = 'int'
2456 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002457
Larry Hastings4a55fc52014-01-12 11:09:57 -08002458class unsigned_long_return_converter(long_return_converter):
2459 type = 'unsigned long'
2460 conversion_fn = 'PyLong_FromUnsignedLong'
2461
2462class unsigned_int_return_converter(unsigned_long_return_converter):
2463 type = 'unsigned int'
2464 cast = '(unsigned long)'
2465
2466class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002467 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002468 conversion_fn = 'PyLong_FromSsize_t'
2469
2470class size_t_return_converter(long_return_converter):
2471 type = 'size_t'
2472 conversion_fn = 'PyLong_FromSize_t'
2473
2474
2475class double_return_converter(CReturnConverter):
2476 type = 'double'
2477 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002478
2479 def render(self, function, data):
2480 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002481 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002482 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002483 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2484
2485class float_return_converter(double_return_converter):
2486 type = 'float'
2487 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002488
2489
2490class DecodeFSDefault_return_converter(CReturnConverter):
2491 type = 'char *'
2492
2493 def render(self, function, data):
2494 self.declare(data)
2495 self.err_occurred_if_null_pointer("_return_value", data)
2496 data.return_conversion.append(
2497 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2498
2499
2500class IndentStack:
2501 def __init__(self):
2502 self.indents = []
2503 self.margin = None
2504
2505 def _ensure(self):
2506 if not self.indents:
2507 fail('IndentStack expected indents, but none are defined.')
2508
2509 def measure(self, line):
2510 """
2511 Returns the length of the line's margin.
2512 """
2513 if '\t' in line:
2514 fail('Tab characters are illegal in the Clinic DSL.')
2515 stripped = line.lstrip()
2516 if not len(stripped):
2517 # we can't tell anything from an empty line
2518 # so just pretend it's indented like our current indent
2519 self._ensure()
2520 return self.indents[-1]
2521 return len(line) - len(stripped)
2522
2523 def infer(self, line):
2524 """
2525 Infer what is now the current margin based on this line.
2526 Returns:
2527 1 if we have indented (or this is the first margin)
2528 0 if the margin has not changed
2529 -N if we have dedented N times
2530 """
2531 indent = self.measure(line)
2532 margin = ' ' * indent
2533 if not self.indents:
2534 self.indents.append(indent)
2535 self.margin = margin
2536 return 1
2537 current = self.indents[-1]
2538 if indent == current:
2539 return 0
2540 if indent > current:
2541 self.indents.append(indent)
2542 self.margin = margin
2543 return 1
2544 # indent < current
2545 if indent not in self.indents:
2546 fail("Illegal outdent.")
2547 outdent_count = 0
2548 while indent != current:
2549 self.indents.pop()
2550 current = self.indents[-1]
2551 outdent_count -= 1
2552 self.margin = margin
2553 return outdent_count
2554
2555 @property
2556 def depth(self):
2557 """
2558 Returns how many margins are currently defined.
2559 """
2560 return len(self.indents)
2561
2562 def indent(self, line):
2563 """
2564 Indents a line by the currently defined margin.
2565 """
2566 return self.margin + line
2567
2568 def dedent(self, line):
2569 """
2570 Dedents a line by the currently defined margin.
2571 (The inverse of 'indent'.)
2572 """
2573 margin = self.margin
2574 indent = self.indents[-1]
2575 if not line.startswith(margin):
2576 fail('Cannot dedent, line does not start with the previous margin:')
2577 return line[indent:]
2578
2579
2580class DSLParser:
2581 def __init__(self, clinic):
2582 self.clinic = clinic
2583
2584 self.directives = {}
2585 for name in dir(self):
2586 # functions that start with directive_ are added to directives
2587 _, s, key = name.partition("directive_")
2588 if s:
2589 self.directives[key] = getattr(self, name)
2590
2591 # functions that start with at_ are too, with an @ in front
2592 _, s, key = name.partition("at_")
2593 if s:
2594 self.directives['@' + key] = getattr(self, name)
2595
2596 self.reset()
2597
2598 def reset(self):
2599 self.function = None
2600 self.state = self.state_dsl_start
2601 self.parameter_indent = None
2602 self.keyword_only = False
2603 self.group = 0
2604 self.parameter_state = self.ps_start
2605 self.indent = IndentStack()
2606 self.kind = CALLABLE
2607 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08002608 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08002609 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07002610
Larry Hastingsebdcb502013-11-23 14:54:00 -08002611 def directive_version(self, required):
2612 global version
2613 if version_comparitor(version, required) < 0:
2614 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2615
Larry Hastings31826802013-10-19 00:09:25 -07002616 def directive_module(self, name):
2617 fields = name.split('.')
2618 new = fields.pop()
2619 module, cls = self.clinic._module_and_class(fields)
2620 if cls:
2621 fail("Can't nest a module inside a class!")
2622 m = Module(name, module)
2623 module.modules[name] = m
2624 self.block.signatures.append(m)
2625
2626 def directive_class(self, name):
2627 fields = name.split('.')
2628 in_classes = False
2629 parent = self
2630 name = fields.pop()
2631 so_far = []
2632 module, cls = self.clinic._module_and_class(fields)
2633
Larry Hastings31826802013-10-19 00:09:25 -07002634 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002635 if cls:
2636 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002637 else:
2638 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002639 self.block.signatures.append(c)
2640
Larry Hastingsbebf7352014-01-17 17:47:17 -08002641 def directive_set(self, name, value):
2642 if name not in ("line_prefix", "line_suffix"):
2643 fail("unknown variable", repr(name))
2644
2645 value = value.format_map({
2646 'block comment start': '/*',
2647 'block comment end': '*/',
2648 })
2649
2650 self.clinic.__dict__[name] = value
2651
2652 def directive_destination(self, name, command, *args):
2653 if command is 'new':
2654 self.clinic.add_destination(name, command, *args)
2655 return
2656
2657 if command is 'clear':
2658 self.clinic.get_destination(name).clear()
2659 fail("unknown destination command", repr(command))
2660
2661
2662 def directive_output(self, field, destination=''):
2663 fd = self.clinic.field_destinations
2664
2665 if field == "preset":
2666 preset = self.clinic.presets.get(destination)
2667 if not preset:
2668 fail("Unknown preset " + repr(destination) + "!")
2669 fd.update(preset)
2670 return
2671
2672 if field == "push":
2673 self.clinic.field_destinations_stack.append(fd.copy())
2674 return
2675
2676 if field == "pop":
2677 if not self.clinic.field_destinations_stack:
2678 fail("Can't 'output pop', stack is empty!")
2679 previous_fd = self.clinic.field_destinations_stack.pop()
2680 fd.update(previous_fd)
2681 return
2682
2683 # secret command for debugging!
2684 if field == "print":
2685 self.block.output.append(pprint.pformat(fd))
2686 self.block.output.append('\n')
2687 return
2688
2689 d = self.clinic.get_destination(destination)
2690
2691 if field == "everything":
2692 for name in list(fd):
2693 fd[name] = d
2694 return
2695
2696 if field not in fd:
2697 fail("Invalid field " + repr(field) + ", must be one of:\n " + ", ".join(valid_fields))
2698 fd[field] = d
2699
2700 def directive_dump(self, name):
2701 self.block.output.append(self.clinic.get_destination(name).dump())
2702
2703 def directive_print(self, *args):
2704 self.block.output.append(' '.join(args))
2705 self.block.output.append('\n')
2706
2707 def directive_preserve(self):
2708 if self.preserve_output:
2709 fail("Can't have preserve twice in one block!")
2710 self.preserve_output = True
2711
Larry Hastings31826802013-10-19 00:09:25 -07002712 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002713 if self.kind is not CALLABLE:
2714 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002715 self.kind = CLASS_METHOD
2716
2717 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002718 if self.kind is not CALLABLE:
2719 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002720 self.kind = STATIC_METHOD
2721
2722 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002723 if self.coexist:
2724 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07002725 self.coexist = True
2726
2727 def parse(self, block):
2728 self.reset()
2729 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08002730 self.saved_output = self.block.output
2731 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07002732 block_start = self.clinic.block_parser.line_number
2733 lines = block.input.split('\n')
2734 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2735 if '\t' in line:
2736 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2737 self.state(line)
2738
2739 self.next(self.state_terminal)
2740 self.state(None)
2741
Larry Hastingsbebf7352014-01-17 17:47:17 -08002742 block.output.extend(self.clinic.language.render(clinic, block.signatures))
2743
2744 if self.preserve_output:
2745 if block.output:
2746 fail("'preserve' only works for blocks that don't produce any output!")
2747 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07002748
2749 @staticmethod
2750 def ignore_line(line):
2751 # ignore comment-only lines
2752 if line.lstrip().startswith('#'):
2753 return True
2754
2755 # Ignore empty lines too
2756 # (but not in docstring sections!)
2757 if not line.strip():
2758 return True
2759
2760 return False
2761
2762 @staticmethod
2763 def calculate_indent(line):
2764 return len(line) - len(line.strip())
2765
2766 def next(self, state, line=None):
2767 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2768 self.state = state
2769 if line is not None:
2770 self.state(line)
2771
2772 def state_dsl_start(self, line):
2773 # self.block = self.ClinicOutputBlock(self)
2774 if self.ignore_line(line):
2775 return
2776 self.next(self.state_modulename_name, line)
2777
2778 def state_modulename_name(self, line):
2779 # looking for declaration, which establishes the leftmost column
2780 # line should be
2781 # modulename.fnname [as c_basename] [-> return annotation]
2782 # square brackets denote optional syntax.
2783 #
Larry Hastings4a714d42014-01-14 22:22:41 -08002784 # alternatively:
2785 # modulename.fnname [as c_basename] = modulename.existing_fn_name
2786 # clones the parameters and return converter from that
2787 # function. you can't modify them. you must enter a
2788 # new docstring.
2789 #
Larry Hastings31826802013-10-19 00:09:25 -07002790 # (but we might find a directive first!)
2791 #
2792 # this line is permitted to start with whitespace.
2793 # we'll call this number of spaces F (for "function").
2794
2795 if not line.strip():
2796 return
2797
2798 self.indent.infer(line)
2799
2800 # is it a directive?
2801 fields = shlex.split(line)
2802 directive_name = fields[0]
2803 directive = self.directives.get(directive_name, None)
2804 if directive:
Larry Hastingsbebf7352014-01-17 17:47:17 -08002805 try:
2806 directive(*fields[1:])
2807 except TypeError as e:
2808 fail(str(e))
Larry Hastings31826802013-10-19 00:09:25 -07002809 return
2810
Larry Hastings4a714d42014-01-14 22:22:41 -08002811 # are we cloning?
2812 before, equals, existing = line.rpartition('=')
2813 if equals:
2814 full_name, _, c_basename = before.partition(' as ')
2815 full_name = full_name.strip()
2816 c_basename = c_basename.strip()
2817 existing = existing.strip()
2818 if (is_legal_py_identifier(full_name) and
2819 (not c_basename or is_legal_c_identifier(c_basename)) and
2820 is_legal_py_identifier(existing)):
2821 # we're cloning!
2822 fields = [x.strip() for x in existing.split('.')]
2823 function_name = fields.pop()
2824 module, cls = self.clinic._module_and_class(fields)
2825
2826 for existing_function in (cls or module).functions:
2827 if existing_function.name == function_name:
2828 break
2829 else:
2830 existing_function = None
2831 if not existing_function:
2832 fail("Couldn't find existing function " + repr(existing) + "!")
2833
2834 fields = [x.strip() for x in full_name.split('.')]
2835 function_name = fields.pop()
2836 module, cls = self.clinic._module_and_class(fields)
2837
2838 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
2839 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
2840 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2841 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
2842
2843 self.function.parameters = existing_function.parameters.copy()
2844
2845 self.block.signatures.append(self.function)
2846 (cls or module).functions.append(self.function)
2847 self.next(self.state_function_docstring)
2848 return
2849
Larry Hastings31826802013-10-19 00:09:25 -07002850 line, _, returns = line.partition('->')
2851
2852 full_name, _, c_basename = line.partition(' as ')
2853 full_name = full_name.strip()
2854 c_basename = c_basename.strip() or None
2855
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002856 if not is_legal_py_identifier(full_name):
2857 fail("Illegal function name: {}".format(full_name))
2858 if c_basename and not is_legal_c_identifier(c_basename):
2859 fail("Illegal C basename: {}".format(c_basename))
2860
Larry Hastings31826802013-10-19 00:09:25 -07002861 if not returns:
2862 return_converter = CReturnConverter()
2863 else:
2864 ast_input = "def x() -> {}: pass".format(returns)
2865 module = None
2866 try:
2867 module = ast.parse(ast_input)
2868 except SyntaxError:
2869 pass
2870 if not module:
2871 fail("Badly-formed annotation for " + full_name + ": " + returns)
2872 try:
2873 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002874 if legacy:
2875 fail("Legacy converter {!r} not allowed as a return converter"
2876 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07002877 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002878 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07002879 return_converter = return_converters[name](**kwargs)
2880 except ValueError:
2881 fail("Badly-formed annotation for " + full_name + ": " + returns)
2882
2883 fields = [x.strip() for x in full_name.split('.')]
2884 function_name = fields.pop()
2885 module, cls = self.clinic._module_and_class(fields)
2886
Larry Hastings8666e652014-01-12 14:12:59 -08002887 fields = full_name.split('.')
2888 if fields[-1] == '__new__':
2889 if (self.kind != CLASS_METHOD) or (not cls):
2890 fail("__new__ must be a class method!")
2891 self.kind = METHOD_NEW
2892 elif fields[-1] == '__init__':
2893 if (self.kind != CALLABLE) or (not cls):
2894 fail("__init__ must be a normal method, not a class or static method!")
2895 self.kind = METHOD_INIT
2896 elif fields[-1] in unsupported_special_methods:
2897 fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
2898
Larry Hastings31826802013-10-19 00:09:25 -07002899 if not module:
2900 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2901 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2902 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2903 self.block.signatures.append(self.function)
Larry Hastings4a714d42014-01-14 22:22:41 -08002904 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07002905 self.next(self.state_parameters_start)
2906
2907 # Now entering the parameters section. The rules, formally stated:
2908 #
2909 # * All lines must be indented with spaces only.
2910 # * The first line must be a parameter declaration.
2911 # * The first line must be indented.
2912 # * This first line establishes the indent for parameters.
2913 # * We'll call this number of spaces P (for "parameter").
2914 # * Thenceforth:
2915 # * Lines indented with P spaces specify a parameter.
2916 # * Lines indented with > P spaces are docstrings for the previous
2917 # parameter.
2918 # * We'll call this number of spaces D (for "docstring").
2919 # * All subsequent lines indented with >= D spaces are stored as
2920 # part of the per-parameter docstring.
2921 # * All lines will have the first D spaces of the indent stripped
2922 # before they are stored.
2923 # * It's illegal to have a line starting with a number of spaces X
2924 # such that P < X < D.
2925 # * A line with < P spaces is the first line of the function
2926 # docstring, which ends processing for parameters and per-parameter
2927 # docstrings.
2928 # * The first line of the function docstring must be at the same
2929 # indent as the function declaration.
2930 # * It's illegal to have any line in the parameters section starting
2931 # with X spaces such that F < X < P. (As before, F is the indent
2932 # of the function declaration.)
2933 #
Larry Hastings31826802013-10-19 00:09:25 -07002934 # Also, currently Argument Clinic places the following restrictions on groups:
2935 # * Each group must contain at least one parameter.
2936 # * Each group may contain at most one group, which must be the furthest
2937 # thing in the group from the required parameters. (The nested group
2938 # must be the first in the group when it's before the required
2939 # parameters, and the last thing in the group when after the required
2940 # parameters.)
2941 # * There may be at most one (top-level) group to the left or right of
2942 # the required parameters.
2943 # * You must specify a slash, and it must be after all parameters.
2944 # (In other words: either all parameters are positional-only,
2945 # or none are.)
2946 #
2947 # Said another way:
2948 # * Each group must contain at least one parameter.
2949 # * All left square brackets before the required parameters must be
2950 # consecutive. (You can't have a left square bracket followed
2951 # by a parameter, then another left square bracket. You can't
2952 # have a left square bracket, a parameter, a right square bracket,
2953 # and then a left square bracket.)
2954 # * All right square brackets after the required parameters must be
2955 # consecutive.
2956 #
2957 # These rules are enforced with a single state variable:
2958 # "parameter_state". (Previously the code was a miasma of ifs and
2959 # separate boolean state variables.) The states are:
2960 #
2961 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2962 # 01 2 3 4 5 6 <- state transitions
2963 #
2964 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2965 # 1: ps_left_square_before. left square brackets before required parameters.
2966 # 2: ps_group_before. in a group, before required parameters.
2967 # 3: ps_required. required parameters. (renumber left groups!)
2968 # 4: ps_group_after. in a group, after required parameters.
2969 # 5: ps_right_square_after. right square brackets after required parameters.
2970 # 6: ps_seen_slash. seen slash.
2971 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2972 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2973
2974 def state_parameters_start(self, line):
2975 if self.ignore_line(line):
2976 return
2977
2978 # if this line is not indented, we have no parameters
2979 if not self.indent.infer(line):
2980 return self.next(self.state_function_docstring, line)
2981
Larry Hastings2a727912014-01-16 11:32:01 -08002982 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07002983 return self.next(self.state_parameter, line)
2984
2985
2986 def to_required(self):
2987 """
2988 Transition to the "required" parameter state.
2989 """
2990 if self.parameter_state != self.ps_required:
2991 self.parameter_state = self.ps_required
2992 for p in self.function.parameters.values():
2993 p.group = -p.group
2994
2995 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08002996 if self.parameter_continuation:
2997 line = self.parameter_continuation + ' ' + line.lstrip()
2998 self.parameter_continuation = ''
2999
Larry Hastings31826802013-10-19 00:09:25 -07003000 if self.ignore_line(line):
3001 return
3002
3003 assert self.indent.depth == 2
3004 indent = self.indent.infer(line)
3005 if indent == -1:
3006 # we outdented, must be to definition column
3007 return self.next(self.state_function_docstring, line)
3008
3009 if indent == 1:
3010 # we indented, must be to new parameter docstring column
3011 return self.next(self.state_parameter_docstring_start, line)
3012
Larry Hastings2a727912014-01-16 11:32:01 -08003013 line = line.rstrip()
3014 if line.endswith('\\'):
3015 self.parameter_continuation = line[:-1]
3016 return
3017
Larry Hastings31826802013-10-19 00:09:25 -07003018 line = line.lstrip()
3019
3020 if line in ('*', '/', '[', ']'):
3021 self.parse_special_symbol(line)
3022 return
3023
3024 if self.parameter_state in (self.ps_start, self.ps_required):
3025 self.to_required()
3026 elif self.parameter_state == self.ps_left_square_before:
3027 self.parameter_state = self.ps_group_before
3028 elif self.parameter_state == self.ps_group_before:
3029 if not self.group:
3030 self.to_required()
3031 elif self.parameter_state == self.ps_group_after:
3032 pass
3033 else:
3034 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3035
Larry Hastings2a727912014-01-16 11:32:01 -08003036 base, equals, default = line.rpartition('=')
3037 if not equals:
3038 base = default
3039 default = None
Larry Hastings31826802013-10-19 00:09:25 -07003040 module = None
3041 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003042 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003043 module = ast.parse(ast_input)
3044 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003045 try:
3046 default = None
3047 ast_input = "def x({}): pass".format(line)
3048 module = ast.parse(ast_input)
3049 except SyntaxError:
3050 pass
Larry Hastings31826802013-10-19 00:09:25 -07003051 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003052 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003053
3054 function_args = module.body[0].args
3055 parameter = function_args.args[0]
3056
Larry Hastings16c51912014-01-07 11:53:01 -08003057 parameter_name = parameter.arg
3058 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3059
Larry Hastings2a727912014-01-16 11:32:01 -08003060 if not default:
3061 value = unspecified
3062 if 'py_default' in kwargs:
3063 fail("You can't specify py_default without specifying a default value!")
3064 else:
3065 default = default.strip()
3066 ast_input = "x = {}".format(default)
3067 try:
3068 module = ast.parse(ast_input)
3069
3070 # blacklist of disallowed ast nodes
3071 class DetectBadNodes(ast.NodeVisitor):
3072 bad = False
3073 def bad_node(self, node):
3074 self.bad = True
3075
3076 # inline function call
3077 visit_Call = bad_node
3078 # inline if statement ("x = 3 if y else z")
3079 visit_IfExp = bad_node
3080
3081 # comprehensions and generator expressions
3082 visit_ListComp = visit_SetComp = bad_node
3083 visit_DictComp = visit_GeneratorExp = bad_node
3084
3085 # literals for advanced types
3086 visit_Dict = visit_Set = bad_node
3087 visit_List = visit_Tuple = bad_node
3088
3089 # "starred": "a = [1, 2, 3]; *a"
3090 visit_Starred = bad_node
3091
3092 # allow ellipsis, for now
3093 # visit_Ellipsis = bad_node
3094
3095 blacklist = DetectBadNodes()
3096 blacklist.visit(module)
3097 if blacklist.bad:
3098 fail("Unsupported expression as default value: " + repr(default))
3099
3100 expr = module.body[0].value
3101 # mild hack: explicitly support NULL as a default value
3102 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3103 value = NULL
3104 py_default = 'None'
3105 c_default = "NULL"
3106 elif (isinstance(expr, ast.BinOp) or
3107 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3108 c_default = kwargs.get("c_default")
3109 if not (isinstance(c_default, str) and c_default):
3110 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3111 py_default = default
3112 value = unknown
3113 elif isinstance(expr, ast.Attribute):
3114 a = []
3115 n = expr
3116 while isinstance(n, ast.Attribute):
3117 a.append(n.attr)
3118 n = n.value
3119 if not isinstance(n, ast.Name):
3120 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3121 a.append(n.id)
3122 py_default = ".".join(reversed(a))
3123
3124 c_default = kwargs.get("c_default")
3125 if not (isinstance(c_default, str) and c_default):
3126 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3127
3128 try:
3129 value = eval(py_default)
3130 except NameError:
3131 value = unknown
3132 else:
3133 value = ast.literal_eval(expr)
3134 py_default = repr(value)
3135 if isinstance(value, (bool, None.__class__)):
3136 c_default = "Py_" + py_default
3137 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003138 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003139 else:
3140 c_default = py_default
3141
3142 except SyntaxError as e:
3143 fail("Syntax error: " + repr(e.text))
3144 except (ValueError, AttributeError):
3145 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003146 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003147 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003148 if not (isinstance(c_default, str) and c_default):
3149 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3150
Larry Hastings2a727912014-01-16 11:32:01 -08003151 kwargs.setdefault('c_default', c_default)
3152 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003153
Larry Hastings31826802013-10-19 00:09:25 -07003154 dict = legacy_converters if legacy else converters
3155 legacy_str = "legacy " if legacy else ""
3156 if name not in dict:
3157 fail('{} is not a valid {}converter'.format(name, legacy_str))
3158 converter = dict[name](parameter_name, self.function, value, **kwargs)
3159
Larry Hastingsebdcb502013-11-23 14:54:00 -08003160 # special case: if it's the self converter,
3161 # don't actually add it to the parameter list
3162 if isinstance(converter, self_converter):
3163 if self.function.parameters or (self.parameter_state != self.ps_required):
3164 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
3165 if self.function.self_converter:
3166 fail("You can't specify the 'self' parameter more than once.")
3167 self.function.self_converter = converter
3168 self.parameter_state = self.ps_start
3169 return
3170
Larry Hastings31826802013-10-19 00:09:25 -07003171 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
3172 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003173
3174 if parameter_name in self.function.parameters:
3175 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003176 self.function.parameters[parameter_name] = p
3177
3178 def parse_converter(self, annotation):
3179 if isinstance(annotation, ast.Str):
3180 return annotation.s, True, {}
3181
3182 if isinstance(annotation, ast.Name):
3183 return annotation.id, False, {}
3184
Larry Hastings4a55fc52014-01-12 11:09:57 -08003185 if not isinstance(annotation, ast.Call):
3186 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003187
3188 name = annotation.func.id
3189 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
3190 return name, False, kwargs
3191
3192 def parse_special_symbol(self, symbol):
3193 if self.parameter_state == self.ps_seen_slash:
3194 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
3195
3196 if symbol == '*':
3197 if self.keyword_only:
3198 fail("Function " + self.function.name + " uses '*' more than once.")
3199 self.keyword_only = True
3200 elif symbol == '[':
3201 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3202 self.parameter_state = self.ps_left_square_before
3203 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3204 self.parameter_state = self.ps_group_after
3205 else:
3206 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3207 self.group += 1
3208 elif symbol == ']':
3209 if not self.group:
3210 fail("Function " + self.function.name + " has a ] without a matching [.")
3211 if not any(p.group == self.group for p in self.function.parameters.values()):
3212 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3213 self.group -= 1
3214 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3215 self.parameter_state = self.ps_group_before
3216 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3217 self.parameter_state = self.ps_right_square_after
3218 else:
3219 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3220 elif symbol == '/':
3221 # ps_required is allowed here, that allows positional-only without option groups
3222 # to work (and have default values!)
3223 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
3224 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3225 if self.keyword_only:
3226 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3227 self.parameter_state = self.ps_seen_slash
3228 # fixup preceeding parameters
3229 for p in self.function.parameters.values():
3230 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
3231 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3232 p.kind = inspect.Parameter.POSITIONAL_ONLY
3233
3234 def state_parameter_docstring_start(self, line):
3235 self.parameter_docstring_indent = len(self.indent.margin)
3236 assert self.indent.depth == 3
3237 return self.next(self.state_parameter_docstring, line)
3238
3239 # every line of the docstring must start with at least F spaces,
3240 # where F > P.
3241 # these F spaces will be stripped.
3242 def state_parameter_docstring(self, line):
3243 stripped = line.strip()
3244 if stripped.startswith('#'):
3245 return
3246
3247 indent = self.indent.measure(line)
3248 if indent < self.parameter_docstring_indent:
3249 self.indent.infer(line)
3250 assert self.indent.depth < 3
3251 if self.indent.depth == 2:
3252 # back to a parameter
3253 return self.next(self.state_parameter, line)
3254 assert self.indent.depth == 1
3255 return self.next(self.state_function_docstring, line)
3256
3257 assert self.function.parameters
3258 last_parameter = next(reversed(list(self.function.parameters.values())))
3259
3260 new_docstring = last_parameter.docstring
3261
3262 if new_docstring:
3263 new_docstring += '\n'
3264 if stripped:
3265 new_docstring += self.indent.dedent(line)
3266
3267 last_parameter.docstring = new_docstring
3268
3269 # the final stanza of the DSL is the docstring.
3270 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003271 if self.group:
3272 fail("Function " + self.function.name + " has a ] without a matching [.")
3273
3274 stripped = line.strip()
3275 if stripped.startswith('#'):
3276 return
3277
3278 new_docstring = self.function.docstring
3279 if new_docstring:
3280 new_docstring += "\n"
3281 if stripped:
3282 line = self.indent.dedent(line).rstrip()
3283 else:
3284 line = ''
3285 new_docstring += line
3286 self.function.docstring = new_docstring
3287
3288 def format_docstring(self):
3289 f = self.function
3290
3291 add, output = text_accumulator()
3292 parameters = list(f.parameters.values())
3293
3294 ##
3295 ## docstring first line
3296 ##
3297
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003298 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07003299 add('(')
3300
3301 # populate "right_bracket_count" field for every parameter
3302 if parameters:
3303 # for now, the only way Clinic supports positional-only parameters
3304 # is if all of them are positional-only.
3305 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
3306 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
3307 assert all(positional_only_parameters)
3308 for p in parameters:
3309 p.right_bracket_count = abs(p.group)
3310 else:
3311 # don't put any right brackets around non-positional-only parameters, ever.
3312 for p in parameters:
3313 p.right_bracket_count = 0
3314
3315 right_bracket_count = 0
3316
3317 def fix_right_bracket_count(desired):
3318 nonlocal right_bracket_count
3319 s = ''
3320 while right_bracket_count < desired:
3321 s += '['
3322 right_bracket_count += 1
3323 while right_bracket_count > desired:
3324 s += ']'
3325 right_bracket_count -= 1
3326 return s
3327
3328 added_star = False
3329 add_comma = False
3330
3331 for p in parameters:
3332 assert p.name
3333
3334 if p.is_keyword_only() and not added_star:
3335 added_star = True
3336 if add_comma:
3337 add(', ')
3338 add('*')
3339
3340 a = [p.name]
3341 if p.converter.is_optional():
3342 a.append('=')
3343 value = p.converter.default
Larry Hastings2a727912014-01-16 11:32:01 -08003344 a.append(p.converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003345 s = fix_right_bracket_count(p.right_bracket_count)
3346 s += "".join(a)
3347 if add_comma:
3348 add(', ')
3349 add(s)
3350 add_comma = True
3351
3352 add(fix_right_bracket_count(0))
3353 add(')')
3354
Larry Hastings2a727912014-01-16 11:32:01 -08003355 # PEP 8 says:
3356 #
3357 # The Python standard library will not use function annotations
3358 # as that would result in a premature commitment to a particular
3359 # annotation style. Instead, the annotations are left for users
3360 # to discover and experiment with useful annotation styles.
3361 #
3362 # therefore this is commented out:
3363 #
3364 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003365 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08003366 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003367
3368 docstring_first_line = output()
3369
3370 # now fix up the places where the brackets look wrong
3371 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
3372
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003373 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07003374 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003375 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07003376 for p in parameters:
3377 if not p.docstring.strip():
3378 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003379 if spacer_line:
3380 add('\n')
3381 else:
3382 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07003383 add(" ")
3384 add(p.name)
3385 add('\n')
3386 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003387 parameters = output()
3388 if parameters:
3389 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07003390
3391 ##
3392 ## docstring body
3393 ##
3394
3395 docstring = f.docstring.rstrip()
3396 lines = [line.rstrip() for line in docstring.split('\n')]
3397
3398 # Enforce the summary line!
3399 # The first line of a docstring should be a summary of the function.
3400 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
3401 # by itself.
3402 #
3403 # Argument Clinic enforces the following rule:
3404 # * either the docstring is empty,
3405 # * or it must have a summary line.
3406 #
3407 # Guido said Clinic should enforce this:
3408 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
3409
3410 if len(lines) >= 2:
3411 if lines[1]:
3412 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
3413 "Every non-blank function docstring must start with\n" +
3414 "a single line summary followed by an empty line.")
3415 elif len(lines) == 1:
3416 # the docstring is only one line right now--the summary line.
3417 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003418 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07003419 lines.append('')
3420
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003421 parameters_marker_count = len(docstring.split('{parameters}')) - 1
3422 if parameters_marker_count > 1:
3423 fail('You may not specify {parameters} more than once in a docstring!')
3424
3425 if not parameters_marker_count:
3426 # insert after summary line
3427 lines.insert(2, '{parameters}')
3428
3429 # insert at front of docstring
3430 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07003431
3432 docstring = "\n".join(lines)
3433
3434 add(docstring)
3435 docstring = output()
3436
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003437 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07003438 docstring = docstring.rstrip()
3439
3440 return docstring
3441
3442 def state_terminal(self, line):
3443 """
3444 Called when processing the block is done.
3445 """
3446 assert not line
3447
3448 if not self.function:
3449 return
3450
Larry Hastings6d2ea212014-01-05 02:50:45 -08003451 if not self.function.self_converter:
3452 self.function.self_converter = self_converter("self", self.function)
3453
Larry Hastings31826802013-10-19 00:09:25 -07003454 if self.keyword_only:
3455 values = self.function.parameters.values()
3456 if not values:
3457 no_parameter_after_star = True
3458 else:
3459 last_parameter = next(reversed(list(values)))
3460 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
3461 if no_parameter_after_star:
3462 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
3463
3464 # remove trailing whitespace from all parameter docstrings
3465 for name, value in self.function.parameters.items():
3466 if not value:
3467 continue
3468 value.docstring = value.docstring.rstrip()
3469
3470 self.function.docstring = self.format_docstring()
3471
3472
3473# maps strings to callables.
3474# the callable should return an object
3475# that implements the clinic parser
3476# interface (__init__ and parse).
3477#
3478# example parsers:
3479# "clinic", handles the Clinic DSL
3480# "python", handles running Python code
3481#
3482parsers = {'clinic' : DSLParser, 'python': PythonParser}
3483
3484
3485clinic = None
3486
3487
3488def main(argv):
3489 import sys
3490
3491 if sys.version_info.major < 3 or sys.version_info.minor < 3:
3492 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
3493
3494 import argparse
3495 cmdline = argparse.ArgumentParser()
3496 cmdline.add_argument("-f", "--force", action='store_true')
3497 cmdline.add_argument("-o", "--output", type=str)
3498 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003499 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07003500 cmdline.add_argument("filename", type=str, nargs="*")
3501 ns = cmdline.parse_args(argv)
3502
3503 if ns.converters:
3504 if ns.filename:
3505 print("Usage error: can't specify --converters and a filename at the same time.")
3506 print()
3507 cmdline.print_usage()
3508 sys.exit(-1)
3509 converters = []
3510 return_converters = []
3511 ignored = set("""
3512 add_c_converter
3513 add_c_return_converter
3514 add_default_legacy_c_converter
3515 add_legacy_c_converter
3516 """.strip().split())
3517 module = globals()
3518 for name in module:
3519 for suffix, ids in (
3520 ("_return_converter", return_converters),
3521 ("_converter", converters),
3522 ):
3523 if name in ignored:
3524 continue
3525 if name.endswith(suffix):
3526 ids.append((name, name[:-len(suffix)]))
3527 break
3528 print()
3529
3530 print("Legacy converters:")
3531 legacy = sorted(legacy_converters)
3532 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
3533 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
3534 print()
3535
3536 for title, attribute, ids in (
3537 ("Converters", 'converter_init', converters),
3538 ("Return converters", 'return_converter_init', return_converters),
3539 ):
3540 print(title + ":")
3541 longest = -1
3542 for name, short_name in ids:
3543 longest = max(longest, len(short_name))
3544 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
3545 cls = module[name]
3546 callable = getattr(cls, attribute, None)
3547 if not callable:
3548 continue
3549 signature = inspect.signature(callable)
3550 parameters = []
3551 for parameter_name, parameter in signature.parameters.items():
3552 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
3553 if parameter.default != inspect.Parameter.empty:
3554 s = '{}={!r}'.format(parameter_name, parameter.default)
3555 else:
3556 s = parameter_name
3557 parameters.append(s)
3558 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07003559 print()
Larry Hastings2a727912014-01-16 11:32:01 -08003560 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
3561 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07003562 sys.exit(0)
3563
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003564 if ns.make:
3565 if ns.output or ns.filename:
3566 print("Usage error: can't use -o or filenames with --make.")
3567 print()
3568 cmdline.print_usage()
3569 sys.exit(-1)
3570 for root, dirs, files in os.walk('.'):
3571 for rcs_dir in ('.svn', '.git', '.hg'):
3572 if rcs_dir in dirs:
3573 dirs.remove(rcs_dir)
3574 for filename in files:
3575 if not filename.endswith('.c'):
3576 continue
3577 path = os.path.join(root, filename)
3578 parse_file(path, verify=not ns.force)
3579 return
3580
Larry Hastings31826802013-10-19 00:09:25 -07003581 if not ns.filename:
3582 cmdline.print_usage()
3583 sys.exit(-1)
3584
3585 if ns.output and len(ns.filename) > 1:
3586 print("Usage error: can't use -o with multiple filenames.")
3587 print()
3588 cmdline.print_usage()
3589 sys.exit(-1)
3590
3591 for filename in ns.filename:
3592 parse_file(filename, output=ns.output, verify=not ns.force)
3593
3594
3595if __name__ == "__main__":
3596 sys.exit(main(sys.argv[1:]))