blob: 0987d568bd6520771f0549dc0b8bd963ae70abcf [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
1896 self.c_default = c_default
1897 self.py_default = py_default
1898
Larry Hastings31826802013-10-19 00:09:25 -07001899 if annotation != unspecified:
1900 fail("The 'annotation' parameter is not currently permitted.")
Larry Hastings31826802013-10-19 00:09:25 -07001901 self.converter_init(**kwargs)
1902
1903 def converter_init(self):
1904 pass
1905
1906 def is_optional(self):
Larry Hastings2a727912014-01-16 11:32:01 -08001907 return (self.default is not unspecified)
Larry Hastings31826802013-10-19 00:09:25 -07001908
1909 def render(self, parameter, data):
1910 """
1911 parameter is a clinic.Parameter instance.
1912 data is a CRenderData instance.
1913 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001914 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08001915 original_name = self.name
1916 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001917
1918 # declarations
1919 d = self.declaration()
1920 data.declarations.append(d)
1921
1922 # initializers
1923 initializers = self.initialize()
1924 if initializers:
1925 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1926
1927 # impl_arguments
1928 s = ("&" if self.impl_by_reference else "") + name
1929 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001930 if self.length:
1931 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001932
1933 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08001934 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001935
1936 # format_units
1937 if self.is_optional() and '|' not in data.format_units:
1938 data.format_units.append('|')
1939 if parameter.is_keyword_only() and '$' not in data.format_units:
1940 data.format_units.append('$')
1941 data.format_units.append(self.format_unit)
1942
1943 # parse_arguments
1944 self.parse_argument(data.parse_arguments)
1945
1946 # impl_parameters
1947 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001948 if self.length:
1949 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001950
1951 # cleanup
1952 cleanup = self.cleanup()
1953 if cleanup:
1954 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1955
Larry Hastingsebdcb502013-11-23 14:54:00 -08001956 def length_name(self):
1957 """Computes the name of the associated "length" variable."""
1958 if not self.length:
1959 return None
1960 return ensure_legal_c_identifier(self.name) + "_length"
1961
Larry Hastings31826802013-10-19 00:09:25 -07001962 # Why is this one broken out separately?
1963 # For "positional-only" function parsing,
1964 # which generates a bunch of PyArg_ParseTuple calls.
1965 def parse_argument(self, list):
1966 assert not (self.converter and self.encoding)
1967 if self.format_unit == 'O&':
1968 assert self.converter
1969 list.append(self.converter)
1970
1971 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08001972 list.append(c_repr(self.encoding))
1973 elif self.subclass_of:
1974 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07001975
Larry Hastingsebdcb502013-11-23 14:54:00 -08001976 legal_name = ensure_legal_c_identifier(self.name)
1977 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001978 list.append(s)
1979
Larry Hastingsebdcb502013-11-23 14:54:00 -08001980 if self.length:
1981 list.append("&" + self.length_name())
1982
Larry Hastings31826802013-10-19 00:09:25 -07001983 #
1984 # All the functions after here are intended as extension points.
1985 #
1986
1987 def simple_declaration(self, by_reference=False):
1988 """
1989 Computes the basic declaration of the variable.
1990 Used in computing the prototype declaration and the
1991 variable declaration.
1992 """
1993 prototype = [self.type]
1994 if by_reference or not self.type.endswith('*'):
1995 prototype.append(" ")
1996 if by_reference:
1997 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001998 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001999 return "".join(prototype)
2000
2001 def declaration(self):
2002 """
2003 The C statement to declare this variable.
2004 """
2005 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08002006 default = self.c_default
2007 if not default and self.parameter.group:
2008 default = self.c_ignored_default
2009 if default:
Larry Hastings31826802013-10-19 00:09:25 -07002010 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08002011 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07002012 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002013 if self.length:
2014 declaration.append('\nPy_ssize_clean_t ')
2015 declaration.append(self.length_name())
2016 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08002017 s = "".join(declaration)
2018 # double up curly-braces, this string will be used
2019 # as part of a format_map() template later
2020 s = s.replace("{", "{{")
2021 s = s.replace("}", "}}")
2022 return s
Larry Hastings31826802013-10-19 00:09:25 -07002023
2024 def initialize(self):
2025 """
2026 The C statements required to set up this variable before parsing.
2027 Returns a string containing this code indented at column 0.
2028 If no initialization is necessary, returns an empty string.
2029 """
2030 return ""
2031
2032 def cleanup(self):
2033 """
2034 The C statements required to clean up after this variable.
2035 Returns a string containing this code indented at column 0.
2036 If no cleanup is necessary, returns an empty string.
2037 """
2038 return ""
2039
2040
2041class bool_converter(CConverter):
2042 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002043 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07002044 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002045 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07002046
2047 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002048 if self.default is not unspecified:
2049 self.default = bool(self.default)
2050 self.c_default = str(int(self.default))
Larry Hastings31826802013-10-19 00:09:25 -07002051
2052class char_converter(CConverter):
2053 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002054 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07002055 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002056 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002057
Larry Hastings4a55fc52014-01-12 11:09:57 -08002058 def converter_init(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002059 if isinstance(self.default, str) and (len(self.default) != 1):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002060 fail("char_converter: illegal default value " + repr(self.default))
2061
2062
Larry Hastings31826802013-10-19 00:09:25 -07002063@add_legacy_c_converter('B', bitwise=True)
2064class byte_converter(CConverter):
Serhiy Storchaka49776ef2014-01-19 00:38:36 +02002065 type = 'unsigned char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002066 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002067 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002068 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07002069
2070 def converter_init(self, *, bitwise=False):
2071 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002072 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07002073
2074class short_converter(CConverter):
2075 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002076 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002077 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002078 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002079
2080class unsigned_short_converter(CConverter):
2081 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002082 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002083 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002084 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002085
2086 def converter_init(self, *, bitwise=False):
2087 if not bitwise:
2088 fail("Unsigned shorts must be bitwise (for now).")
2089
Larry Hastingsebdcb502013-11-23 14:54:00 -08002090@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07002091class int_converter(CConverter):
2092 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002093 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002094 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002095 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002096
Larry Hastingsebdcb502013-11-23 14:54:00 -08002097 def converter_init(self, *, types='int'):
2098 if types == 'str':
2099 self.format_unit = 'C'
2100 elif types != 'int':
2101 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07002102
2103class unsigned_int_converter(CConverter):
2104 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002105 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002106 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002107 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002108
2109 def converter_init(self, *, bitwise=False):
2110 if not bitwise:
2111 fail("Unsigned ints must be bitwise (for now).")
2112
2113class long_converter(CConverter):
2114 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002115 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002116 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002117 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002118
2119class unsigned_long_converter(CConverter):
2120 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002121 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002122 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002123 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002124
2125 def converter_init(self, *, bitwise=False):
2126 if not bitwise:
2127 fail("Unsigned longs must be bitwise (for now).")
2128
2129class PY_LONG_LONG_converter(CConverter):
2130 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002131 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002132 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002133 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002134
2135class unsigned_PY_LONG_LONG_converter(CConverter):
2136 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002137 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002138 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002139 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002140
2141 def converter_init(self, *, bitwise=False):
2142 if not bitwise:
2143 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
2144
2145class Py_ssize_t_converter(CConverter):
2146 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002147 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07002148 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002149 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07002150
2151
2152class float_converter(CConverter):
2153 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002154 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002155 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002156 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002157
2158class double_converter(CConverter):
2159 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002160 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07002161 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002162 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07002163
2164
2165class Py_complex_converter(CConverter):
2166 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002167 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07002168 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08002169 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07002170
2171
2172class object_converter(CConverter):
2173 type = 'PyObject *'
2174 format_unit = 'O'
2175
Larry Hastings4a55fc52014-01-12 11:09:57 -08002176 def converter_init(self, *, converter=None, type=None, subclass_of=None):
2177 if converter:
2178 if subclass_of:
2179 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
2180 self.format_unit = 'O&'
2181 self.converter = converter
2182 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07002183 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08002184 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08002185
Larry Hastings77561cc2014-01-07 12:13:13 -08002186 if type is not None:
2187 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07002188
2189
Larry Hastingsebdcb502013-11-23 14:54:00 -08002190@add_legacy_c_converter('s#', length=True)
Larry Hastings2a727912014-01-16 11:32:01 -08002191@add_legacy_c_converter('y', types="bytes")
2192@add_legacy_c_converter('y#', types="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002193@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002194@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002195class str_converter(CConverter):
2196 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002197 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002198 format_unit = 's'
2199
Larry Hastingsebdcb502013-11-23 14:54:00 -08002200 def converter_init(self, *, encoding=None, types="str",
2201 length=False, nullable=False, zeroes=False):
2202
2203 types = set(types.strip().split())
2204 bytes_type = set(("bytes",))
2205 str_type = set(("str",))
2206 all_3_type = set(("bytearray",)) | bytes_type | str_type
2207 is_bytes = types == bytes_type
2208 is_str = types == str_type
2209 is_all_3 = types == all_3_type
2210
2211 self.length = bool(length)
2212 format_unit = None
2213
2214 if encoding:
2215 self.encoding = encoding
2216
2217 if is_str and not (length or zeroes or nullable):
2218 format_unit = 'es'
2219 elif is_all_3 and not (length or zeroes or nullable):
2220 format_unit = 'et'
2221 elif is_str and length and zeroes and not nullable:
2222 format_unit = 'es#'
2223 elif is_all_3 and length and not (nullable or zeroes):
2224 format_unit = 'et#'
2225
2226 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08002227 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08002228 # TODO set pointer to NULL
2229 # TODO add cleanup for buffer
2230 pass
2231
2232 else:
2233 if zeroes:
2234 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
2235
2236 if is_bytes and not (nullable or length):
2237 format_unit = 'y'
2238 elif is_bytes and length and not nullable:
2239 format_unit = 'y#'
2240 elif is_str and not (nullable or length):
2241 format_unit = 's'
2242 elif is_str and length and not nullable:
2243 format_unit = 's#'
2244 elif is_str and nullable and not length:
2245 format_unit = 'z'
2246 elif is_str and nullable and length:
2247 format_unit = 'z#'
2248
2249 if not format_unit:
2250 fail("str_converter: illegal combination of arguments")
2251 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002252
2253
2254class PyBytesObject_converter(CConverter):
2255 type = 'PyBytesObject *'
2256 format_unit = 'S'
2257
2258class PyByteArrayObject_converter(CConverter):
2259 type = 'PyByteArrayObject *'
2260 format_unit = 'Y'
2261
2262class unicode_converter(CConverter):
2263 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002264 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002265 format_unit = 'U'
2266
Larry Hastingsebdcb502013-11-23 14:54:00 -08002267@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002268@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08002269@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07002270class Py_UNICODE_converter(CConverter):
2271 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002272 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07002273 format_unit = 'u'
2274
Larry Hastingsebdcb502013-11-23 14:54:00 -08002275 def converter_init(self, *, nullable=False, length=False):
2276 format_unit = 'Z' if nullable else 'u'
2277 if length:
2278 format_unit += '#'
2279 self.length = True
2280 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002281
Larry Hastingsebdcb502013-11-23 14:54:00 -08002282#
2283# We define three string conventions for buffer types in the 'types' argument:
2284# 'buffer' : any object supporting the buffer interface
2285# 'rwbuffer': any object supporting the buffer interface, but must be writeable
2286# 'robuffer': any object supporting the buffer interface, but must not be writeable
2287#
2288@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
2289@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
2290@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07002291class Py_buffer_converter(CConverter):
2292 type = 'Py_buffer'
2293 format_unit = 'y*'
2294 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08002295 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07002296
Larry Hastingsebdcb502013-11-23 14:54:00 -08002297 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002298 if self.default not in (unspecified, None):
2299 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08002300 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08002301 types = set(types.strip().split())
2302 bytes_type = set(('bytes',))
2303 bytearray_type = set(('bytearray',))
2304 buffer_type = set(('buffer',))
2305 rwbuffer_type = set(('rwbuffer',))
2306 robuffer_type = set(('robuffer',))
2307 str_type = set(('str',))
2308 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
2309
2310 format_unit = None
2311 if types == (str_type | bytes_bytearray_buffer_type):
2312 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07002313 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08002314 if nullable:
2315 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
2316 elif types == (bytes_bytearray_buffer_type):
2317 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002318 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002319 format_unit = 'w*'
2320 if not format_unit:
2321 fail("Py_buffer_converter: illegal combination of arguments")
2322
2323 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07002324
2325 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002326 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002327 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08002328
2329
2330class self_converter(CConverter):
2331 """
2332 A special-case converter:
2333 this is the default converter used for "self".
2334 """
2335 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08002336 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002337 f = self.function
Larry Hastings8666e652014-01-12 14:12:59 -08002338 if f.kind in (CALLABLE, METHOD_INIT):
Larry Hastingsebdcb502013-11-23 14:54:00 -08002339 if f.cls:
2340 self.name = "self"
2341 else:
2342 self.name = "module"
2343 self.type = "PyModuleDef *"
2344 elif f.kind == STATIC_METHOD:
2345 self.name = "null"
2346 self.type = "void *"
2347 elif f.kind == CLASS_METHOD:
2348 self.name = "cls"
2349 self.type = "PyTypeObject *"
Larry Hastings8666e652014-01-12 14:12:59 -08002350 elif f.kind == METHOD_NEW:
2351 self.name = "type"
2352 self.type = "PyTypeObject *"
Larry Hastingsebdcb502013-11-23 14:54:00 -08002353
Larry Hastings78cf85c2014-01-04 12:44:57 -08002354 if type:
2355 self.type = type
2356
Larry Hastingsebdcb502013-11-23 14:54:00 -08002357 def render(self, parameter, data):
2358 fail("render() should never be called on self_converter instances")
2359
Larry Hastings31826802013-10-19 00:09:25 -07002360
2361
2362def add_c_return_converter(f, name=None):
2363 if not name:
2364 name = f.__name__
2365 if not name.endswith('_return_converter'):
2366 return f
2367 name = name[:-len('_return_converter')]
2368 return_converters[name] = f
2369 return f
2370
2371
2372class CReturnConverterAutoRegister(type):
2373 def __init__(cls, name, bases, classdict):
2374 add_c_return_converter(cls)
2375
2376class CReturnConverter(metaclass=CReturnConverterAutoRegister):
2377
Larry Hastings78cf85c2014-01-04 12:44:57 -08002378 # The C type to use for this variable.
2379 # 'type' should be a Python string specifying the type, e.g. "int".
2380 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07002381 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08002382
2383 # The Python default value for this parameter, as a Python value.
2384 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07002385 default = None
2386
Larry Hastings2a727912014-01-16 11:32:01 -08002387 def __init__(self, *, py_default=None, **kwargs):
2388 self.py_default = py_default
Larry Hastings31826802013-10-19 00:09:25 -07002389 try:
2390 self.return_converter_init(**kwargs)
2391 except TypeError as e:
2392 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2393 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2394
2395 def return_converter_init(self):
2396 pass
2397
2398 def declare(self, data, name="_return_value"):
2399 line = []
2400 add = line.append
2401 add(self.type)
2402 if not self.type.endswith('*'):
2403 add(' ')
2404 add(name + ';')
2405 data.declarations.append(''.join(line))
2406 data.return_value = name
2407
2408 def err_occurred_if(self, expr, data):
2409 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2410
2411 def err_occurred_if_null_pointer(self, variable, data):
2412 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2413
2414 def render(self, function, data):
2415 """
2416 function is a clinic.Function instance.
2417 data is a CRenderData instance.
2418 """
2419 pass
2420
2421add_c_return_converter(CReturnConverter, 'object')
2422
Larry Hastings78cf85c2014-01-04 12:44:57 -08002423class NoneType_return_converter(CReturnConverter):
2424 def render(self, function, data):
2425 self.declare(data)
2426 data.return_conversion.append('''
2427if (_return_value != Py_None)
2428 goto exit;
2429return_value = Py_None;
2430Py_INCREF(Py_None);
2431'''.strip())
2432
Larry Hastings4a55fc52014-01-12 11:09:57 -08002433class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002434 type = 'int'
2435
2436 def render(self, function, data):
2437 self.declare(data)
2438 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002439 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002440
2441class long_return_converter(CReturnConverter):
2442 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002443 conversion_fn = 'PyLong_FromLong'
2444 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002445
2446 def render(self, function, data):
2447 self.declare(data)
2448 self.err_occurred_if("_return_value == -1", data)
2449 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002450 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002451
Larry Hastings4a55fc52014-01-12 11:09:57 -08002452class int_return_converter(long_return_converter):
2453 type = 'int'
2454 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002455
Larry Hastings4a55fc52014-01-12 11:09:57 -08002456class unsigned_long_return_converter(long_return_converter):
2457 type = 'unsigned long'
2458 conversion_fn = 'PyLong_FromUnsignedLong'
2459
2460class unsigned_int_return_converter(unsigned_long_return_converter):
2461 type = 'unsigned int'
2462 cast = '(unsigned long)'
2463
2464class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002465 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002466 conversion_fn = 'PyLong_FromSsize_t'
2467
2468class size_t_return_converter(long_return_converter):
2469 type = 'size_t'
2470 conversion_fn = 'PyLong_FromSize_t'
2471
2472
2473class double_return_converter(CReturnConverter):
2474 type = 'double'
2475 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002476
2477 def render(self, function, data):
2478 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002479 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002480 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002481 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2482
2483class float_return_converter(double_return_converter):
2484 type = 'float'
2485 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002486
2487
2488class DecodeFSDefault_return_converter(CReturnConverter):
2489 type = 'char *'
2490
2491 def render(self, function, data):
2492 self.declare(data)
2493 self.err_occurred_if_null_pointer("_return_value", data)
2494 data.return_conversion.append(
2495 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2496
2497
2498class IndentStack:
2499 def __init__(self):
2500 self.indents = []
2501 self.margin = None
2502
2503 def _ensure(self):
2504 if not self.indents:
2505 fail('IndentStack expected indents, but none are defined.')
2506
2507 def measure(self, line):
2508 """
2509 Returns the length of the line's margin.
2510 """
2511 if '\t' in line:
2512 fail('Tab characters are illegal in the Clinic DSL.')
2513 stripped = line.lstrip()
2514 if not len(stripped):
2515 # we can't tell anything from an empty line
2516 # so just pretend it's indented like our current indent
2517 self._ensure()
2518 return self.indents[-1]
2519 return len(line) - len(stripped)
2520
2521 def infer(self, line):
2522 """
2523 Infer what is now the current margin based on this line.
2524 Returns:
2525 1 if we have indented (or this is the first margin)
2526 0 if the margin has not changed
2527 -N if we have dedented N times
2528 """
2529 indent = self.measure(line)
2530 margin = ' ' * indent
2531 if not self.indents:
2532 self.indents.append(indent)
2533 self.margin = margin
2534 return 1
2535 current = self.indents[-1]
2536 if indent == current:
2537 return 0
2538 if indent > current:
2539 self.indents.append(indent)
2540 self.margin = margin
2541 return 1
2542 # indent < current
2543 if indent not in self.indents:
2544 fail("Illegal outdent.")
2545 outdent_count = 0
2546 while indent != current:
2547 self.indents.pop()
2548 current = self.indents[-1]
2549 outdent_count -= 1
2550 self.margin = margin
2551 return outdent_count
2552
2553 @property
2554 def depth(self):
2555 """
2556 Returns how many margins are currently defined.
2557 """
2558 return len(self.indents)
2559
2560 def indent(self, line):
2561 """
2562 Indents a line by the currently defined margin.
2563 """
2564 return self.margin + line
2565
2566 def dedent(self, line):
2567 """
2568 Dedents a line by the currently defined margin.
2569 (The inverse of 'indent'.)
2570 """
2571 margin = self.margin
2572 indent = self.indents[-1]
2573 if not line.startswith(margin):
2574 fail('Cannot dedent, line does not start with the previous margin:')
2575 return line[indent:]
2576
2577
2578class DSLParser:
2579 def __init__(self, clinic):
2580 self.clinic = clinic
2581
2582 self.directives = {}
2583 for name in dir(self):
2584 # functions that start with directive_ are added to directives
2585 _, s, key = name.partition("directive_")
2586 if s:
2587 self.directives[key] = getattr(self, name)
2588
2589 # functions that start with at_ are too, with an @ in front
2590 _, s, key = name.partition("at_")
2591 if s:
2592 self.directives['@' + key] = getattr(self, name)
2593
2594 self.reset()
2595
2596 def reset(self):
2597 self.function = None
2598 self.state = self.state_dsl_start
2599 self.parameter_indent = None
2600 self.keyword_only = False
2601 self.group = 0
2602 self.parameter_state = self.ps_start
2603 self.indent = IndentStack()
2604 self.kind = CALLABLE
2605 self.coexist = False
Larry Hastings2a727912014-01-16 11:32:01 -08002606 self.parameter_continuation = ''
Larry Hastingsbebf7352014-01-17 17:47:17 -08002607 self.preserve_output = False
Larry Hastings31826802013-10-19 00:09:25 -07002608
Larry Hastingsebdcb502013-11-23 14:54:00 -08002609 def directive_version(self, required):
2610 global version
2611 if version_comparitor(version, required) < 0:
2612 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2613
Larry Hastings31826802013-10-19 00:09:25 -07002614 def directive_module(self, name):
2615 fields = name.split('.')
2616 new = fields.pop()
2617 module, cls = self.clinic._module_and_class(fields)
2618 if cls:
2619 fail("Can't nest a module inside a class!")
2620 m = Module(name, module)
2621 module.modules[name] = m
2622 self.block.signatures.append(m)
2623
2624 def directive_class(self, name):
2625 fields = name.split('.')
2626 in_classes = False
2627 parent = self
2628 name = fields.pop()
2629 so_far = []
2630 module, cls = self.clinic._module_and_class(fields)
2631
Larry Hastings31826802013-10-19 00:09:25 -07002632 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002633 if cls:
2634 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002635 else:
2636 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002637 self.block.signatures.append(c)
2638
Larry Hastingsbebf7352014-01-17 17:47:17 -08002639 def directive_set(self, name, value):
2640 if name not in ("line_prefix", "line_suffix"):
2641 fail("unknown variable", repr(name))
2642
2643 value = value.format_map({
2644 'block comment start': '/*',
2645 'block comment end': '*/',
2646 })
2647
2648 self.clinic.__dict__[name] = value
2649
2650 def directive_destination(self, name, command, *args):
2651 if command is 'new':
2652 self.clinic.add_destination(name, command, *args)
2653 return
2654
2655 if command is 'clear':
2656 self.clinic.get_destination(name).clear()
2657 fail("unknown destination command", repr(command))
2658
2659
2660 def directive_output(self, field, destination=''):
2661 fd = self.clinic.field_destinations
2662
2663 if field == "preset":
2664 preset = self.clinic.presets.get(destination)
2665 if not preset:
2666 fail("Unknown preset " + repr(destination) + "!")
2667 fd.update(preset)
2668 return
2669
2670 if field == "push":
2671 self.clinic.field_destinations_stack.append(fd.copy())
2672 return
2673
2674 if field == "pop":
2675 if not self.clinic.field_destinations_stack:
2676 fail("Can't 'output pop', stack is empty!")
2677 previous_fd = self.clinic.field_destinations_stack.pop()
2678 fd.update(previous_fd)
2679 return
2680
2681 # secret command for debugging!
2682 if field == "print":
2683 self.block.output.append(pprint.pformat(fd))
2684 self.block.output.append('\n')
2685 return
2686
2687 d = self.clinic.get_destination(destination)
2688
2689 if field == "everything":
2690 for name in list(fd):
2691 fd[name] = d
2692 return
2693
2694 if field not in fd:
2695 fail("Invalid field " + repr(field) + ", must be one of:\n " + ", ".join(valid_fields))
2696 fd[field] = d
2697
2698 def directive_dump(self, name):
2699 self.block.output.append(self.clinic.get_destination(name).dump())
2700
2701 def directive_print(self, *args):
2702 self.block.output.append(' '.join(args))
2703 self.block.output.append('\n')
2704
2705 def directive_preserve(self):
2706 if self.preserve_output:
2707 fail("Can't have preserve twice in one block!")
2708 self.preserve_output = True
2709
Larry Hastings31826802013-10-19 00:09:25 -07002710 def at_classmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002711 if self.kind is not CALLABLE:
2712 fail("Can't set @classmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002713 self.kind = CLASS_METHOD
2714
2715 def at_staticmethod(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002716 if self.kind is not CALLABLE:
2717 fail("Can't set @staticmethod, function is not a normal callable")
Larry Hastings31826802013-10-19 00:09:25 -07002718 self.kind = STATIC_METHOD
2719
2720 def at_coexist(self):
Larry Hastings2a727912014-01-16 11:32:01 -08002721 if self.coexist:
2722 fail("Called @coexist twice!")
Larry Hastings31826802013-10-19 00:09:25 -07002723 self.coexist = True
2724
2725 def parse(self, block):
2726 self.reset()
2727 self.block = block
Larry Hastingsbebf7352014-01-17 17:47:17 -08002728 self.saved_output = self.block.output
2729 block.output = []
Larry Hastings31826802013-10-19 00:09:25 -07002730 block_start = self.clinic.block_parser.line_number
2731 lines = block.input.split('\n')
2732 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2733 if '\t' in line:
2734 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2735 self.state(line)
2736
2737 self.next(self.state_terminal)
2738 self.state(None)
2739
Larry Hastingsbebf7352014-01-17 17:47:17 -08002740 block.output.extend(self.clinic.language.render(clinic, block.signatures))
2741
2742 if self.preserve_output:
2743 if block.output:
2744 fail("'preserve' only works for blocks that don't produce any output!")
2745 block.output = self.saved_output
Larry Hastings31826802013-10-19 00:09:25 -07002746
2747 @staticmethod
2748 def ignore_line(line):
2749 # ignore comment-only lines
2750 if line.lstrip().startswith('#'):
2751 return True
2752
2753 # Ignore empty lines too
2754 # (but not in docstring sections!)
2755 if not line.strip():
2756 return True
2757
2758 return False
2759
2760 @staticmethod
2761 def calculate_indent(line):
2762 return len(line) - len(line.strip())
2763
2764 def next(self, state, line=None):
2765 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2766 self.state = state
2767 if line is not None:
2768 self.state(line)
2769
2770 def state_dsl_start(self, line):
2771 # self.block = self.ClinicOutputBlock(self)
2772 if self.ignore_line(line):
2773 return
2774 self.next(self.state_modulename_name, line)
2775
2776 def state_modulename_name(self, line):
2777 # looking for declaration, which establishes the leftmost column
2778 # line should be
2779 # modulename.fnname [as c_basename] [-> return annotation]
2780 # square brackets denote optional syntax.
2781 #
Larry Hastings4a714d42014-01-14 22:22:41 -08002782 # alternatively:
2783 # modulename.fnname [as c_basename] = modulename.existing_fn_name
2784 # clones the parameters and return converter from that
2785 # function. you can't modify them. you must enter a
2786 # new docstring.
2787 #
Larry Hastings31826802013-10-19 00:09:25 -07002788 # (but we might find a directive first!)
2789 #
2790 # this line is permitted to start with whitespace.
2791 # we'll call this number of spaces F (for "function").
2792
2793 if not line.strip():
2794 return
2795
2796 self.indent.infer(line)
2797
2798 # is it a directive?
2799 fields = shlex.split(line)
2800 directive_name = fields[0]
2801 directive = self.directives.get(directive_name, None)
2802 if directive:
Larry Hastingsbebf7352014-01-17 17:47:17 -08002803 try:
2804 directive(*fields[1:])
2805 except TypeError as e:
2806 fail(str(e))
Larry Hastings31826802013-10-19 00:09:25 -07002807 return
2808
Larry Hastings4a714d42014-01-14 22:22:41 -08002809 # are we cloning?
2810 before, equals, existing = line.rpartition('=')
2811 if equals:
2812 full_name, _, c_basename = before.partition(' as ')
2813 full_name = full_name.strip()
2814 c_basename = c_basename.strip()
2815 existing = existing.strip()
2816 if (is_legal_py_identifier(full_name) and
2817 (not c_basename or is_legal_c_identifier(c_basename)) and
2818 is_legal_py_identifier(existing)):
2819 # we're cloning!
2820 fields = [x.strip() for x in existing.split('.')]
2821 function_name = fields.pop()
2822 module, cls = self.clinic._module_and_class(fields)
2823
2824 for existing_function in (cls or module).functions:
2825 if existing_function.name == function_name:
2826 break
2827 else:
2828 existing_function = None
2829 if not existing_function:
2830 fail("Couldn't find existing function " + repr(existing) + "!")
2831
2832 fields = [x.strip() for x in full_name.split('.')]
2833 function_name = fields.pop()
2834 module, cls = self.clinic._module_and_class(fields)
2835
2836 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
2837 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
2838 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2839 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
2840
2841 self.function.parameters = existing_function.parameters.copy()
2842
2843 self.block.signatures.append(self.function)
2844 (cls or module).functions.append(self.function)
2845 self.next(self.state_function_docstring)
2846 return
2847
Larry Hastings31826802013-10-19 00:09:25 -07002848 line, _, returns = line.partition('->')
2849
2850 full_name, _, c_basename = line.partition(' as ')
2851 full_name = full_name.strip()
2852 c_basename = c_basename.strip() or None
2853
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002854 if not is_legal_py_identifier(full_name):
2855 fail("Illegal function name: {}".format(full_name))
2856 if c_basename and not is_legal_c_identifier(c_basename):
2857 fail("Illegal C basename: {}".format(c_basename))
2858
Larry Hastings31826802013-10-19 00:09:25 -07002859 if not returns:
2860 return_converter = CReturnConverter()
2861 else:
2862 ast_input = "def x() -> {}: pass".format(returns)
2863 module = None
2864 try:
2865 module = ast.parse(ast_input)
2866 except SyntaxError:
2867 pass
2868 if not module:
2869 fail("Badly-formed annotation for " + full_name + ": " + returns)
2870 try:
2871 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002872 if legacy:
2873 fail("Legacy converter {!r} not allowed as a return converter"
2874 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07002875 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002876 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07002877 return_converter = return_converters[name](**kwargs)
2878 except ValueError:
2879 fail("Badly-formed annotation for " + full_name + ": " + returns)
2880
2881 fields = [x.strip() for x in full_name.split('.')]
2882 function_name = fields.pop()
2883 module, cls = self.clinic._module_and_class(fields)
2884
Larry Hastings8666e652014-01-12 14:12:59 -08002885 fields = full_name.split('.')
2886 if fields[-1] == '__new__':
2887 if (self.kind != CLASS_METHOD) or (not cls):
2888 fail("__new__ must be a class method!")
2889 self.kind = METHOD_NEW
2890 elif fields[-1] == '__init__':
2891 if (self.kind != CALLABLE) or (not cls):
2892 fail("__init__ must be a normal method, not a class or static method!")
2893 self.kind = METHOD_INIT
2894 elif fields[-1] in unsupported_special_methods:
2895 fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
2896
Larry Hastings31826802013-10-19 00:09:25 -07002897 if not module:
2898 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2899 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2900 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2901 self.block.signatures.append(self.function)
Larry Hastings4a714d42014-01-14 22:22:41 -08002902 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07002903 self.next(self.state_parameters_start)
2904
2905 # Now entering the parameters section. The rules, formally stated:
2906 #
2907 # * All lines must be indented with spaces only.
2908 # * The first line must be a parameter declaration.
2909 # * The first line must be indented.
2910 # * This first line establishes the indent for parameters.
2911 # * We'll call this number of spaces P (for "parameter").
2912 # * Thenceforth:
2913 # * Lines indented with P spaces specify a parameter.
2914 # * Lines indented with > P spaces are docstrings for the previous
2915 # parameter.
2916 # * We'll call this number of spaces D (for "docstring").
2917 # * All subsequent lines indented with >= D spaces are stored as
2918 # part of the per-parameter docstring.
2919 # * All lines will have the first D spaces of the indent stripped
2920 # before they are stored.
2921 # * It's illegal to have a line starting with a number of spaces X
2922 # such that P < X < D.
2923 # * A line with < P spaces is the first line of the function
2924 # docstring, which ends processing for parameters and per-parameter
2925 # docstrings.
2926 # * The first line of the function docstring must be at the same
2927 # indent as the function declaration.
2928 # * It's illegal to have any line in the parameters section starting
2929 # with X spaces such that F < X < P. (As before, F is the indent
2930 # of the function declaration.)
2931 #
Larry Hastings31826802013-10-19 00:09:25 -07002932 # Also, currently Argument Clinic places the following restrictions on groups:
2933 # * Each group must contain at least one parameter.
2934 # * Each group may contain at most one group, which must be the furthest
2935 # thing in the group from the required parameters. (The nested group
2936 # must be the first in the group when it's before the required
2937 # parameters, and the last thing in the group when after the required
2938 # parameters.)
2939 # * There may be at most one (top-level) group to the left or right of
2940 # the required parameters.
2941 # * You must specify a slash, and it must be after all parameters.
2942 # (In other words: either all parameters are positional-only,
2943 # or none are.)
2944 #
2945 # Said another way:
2946 # * Each group must contain at least one parameter.
2947 # * All left square brackets before the required parameters must be
2948 # consecutive. (You can't have a left square bracket followed
2949 # by a parameter, then another left square bracket. You can't
2950 # have a left square bracket, a parameter, a right square bracket,
2951 # and then a left square bracket.)
2952 # * All right square brackets after the required parameters must be
2953 # consecutive.
2954 #
2955 # These rules are enforced with a single state variable:
2956 # "parameter_state". (Previously the code was a miasma of ifs and
2957 # separate boolean state variables.) The states are:
2958 #
2959 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2960 # 01 2 3 4 5 6 <- state transitions
2961 #
2962 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2963 # 1: ps_left_square_before. left square brackets before required parameters.
2964 # 2: ps_group_before. in a group, before required parameters.
2965 # 3: ps_required. required parameters. (renumber left groups!)
2966 # 4: ps_group_after. in a group, after required parameters.
2967 # 5: ps_right_square_after. right square brackets after required parameters.
2968 # 6: ps_seen_slash. seen slash.
2969 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2970 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2971
2972 def state_parameters_start(self, line):
2973 if self.ignore_line(line):
2974 return
2975
2976 # if this line is not indented, we have no parameters
2977 if not self.indent.infer(line):
2978 return self.next(self.state_function_docstring, line)
2979
Larry Hastings2a727912014-01-16 11:32:01 -08002980 self.parameter_continuation = ''
Larry Hastings31826802013-10-19 00:09:25 -07002981 return self.next(self.state_parameter, line)
2982
2983
2984 def to_required(self):
2985 """
2986 Transition to the "required" parameter state.
2987 """
2988 if self.parameter_state != self.ps_required:
2989 self.parameter_state = self.ps_required
2990 for p in self.function.parameters.values():
2991 p.group = -p.group
2992
2993 def state_parameter(self, line):
Larry Hastings2a727912014-01-16 11:32:01 -08002994 if self.parameter_continuation:
2995 line = self.parameter_continuation + ' ' + line.lstrip()
2996 self.parameter_continuation = ''
2997
Larry Hastings31826802013-10-19 00:09:25 -07002998 if self.ignore_line(line):
2999 return
3000
3001 assert self.indent.depth == 2
3002 indent = self.indent.infer(line)
3003 if indent == -1:
3004 # we outdented, must be to definition column
3005 return self.next(self.state_function_docstring, line)
3006
3007 if indent == 1:
3008 # we indented, must be to new parameter docstring column
3009 return self.next(self.state_parameter_docstring_start, line)
3010
Larry Hastings2a727912014-01-16 11:32:01 -08003011 line = line.rstrip()
3012 if line.endswith('\\'):
3013 self.parameter_continuation = line[:-1]
3014 return
3015
Larry Hastings31826802013-10-19 00:09:25 -07003016 line = line.lstrip()
3017
3018 if line in ('*', '/', '[', ']'):
3019 self.parse_special_symbol(line)
3020 return
3021
3022 if self.parameter_state in (self.ps_start, self.ps_required):
3023 self.to_required()
3024 elif self.parameter_state == self.ps_left_square_before:
3025 self.parameter_state = self.ps_group_before
3026 elif self.parameter_state == self.ps_group_before:
3027 if not self.group:
3028 self.to_required()
3029 elif self.parameter_state == self.ps_group_after:
3030 pass
3031 else:
3032 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3033
Larry Hastings2a727912014-01-16 11:32:01 -08003034 base, equals, default = line.rpartition('=')
3035 if not equals:
3036 base = default
3037 default = None
Larry Hastings31826802013-10-19 00:09:25 -07003038 module = None
3039 try:
Larry Hastings2a727912014-01-16 11:32:01 -08003040 ast_input = "def x({}): pass".format(base)
Larry Hastings31826802013-10-19 00:09:25 -07003041 module = ast.parse(ast_input)
3042 except SyntaxError:
Larry Hastings2a727912014-01-16 11:32:01 -08003043 try:
3044 default = None
3045 ast_input = "def x({}): pass".format(line)
3046 module = ast.parse(ast_input)
3047 except SyntaxError:
3048 pass
Larry Hastings31826802013-10-19 00:09:25 -07003049 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07003050 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07003051
3052 function_args = module.body[0].args
3053 parameter = function_args.args[0]
3054
Larry Hastings16c51912014-01-07 11:53:01 -08003055 parameter_name = parameter.arg
3056 name, legacy, kwargs = self.parse_converter(parameter.annotation)
3057
Larry Hastings2a727912014-01-16 11:32:01 -08003058 if not default:
3059 value = unspecified
3060 if 'py_default' in kwargs:
3061 fail("You can't specify py_default without specifying a default value!")
3062 else:
3063 default = default.strip()
3064 ast_input = "x = {}".format(default)
3065 try:
3066 module = ast.parse(ast_input)
3067
3068 # blacklist of disallowed ast nodes
3069 class DetectBadNodes(ast.NodeVisitor):
3070 bad = False
3071 def bad_node(self, node):
3072 self.bad = True
3073
3074 # inline function call
3075 visit_Call = bad_node
3076 # inline if statement ("x = 3 if y else z")
3077 visit_IfExp = bad_node
3078
3079 # comprehensions and generator expressions
3080 visit_ListComp = visit_SetComp = bad_node
3081 visit_DictComp = visit_GeneratorExp = bad_node
3082
3083 # literals for advanced types
3084 visit_Dict = visit_Set = bad_node
3085 visit_List = visit_Tuple = bad_node
3086
3087 # "starred": "a = [1, 2, 3]; *a"
3088 visit_Starred = bad_node
3089
3090 # allow ellipsis, for now
3091 # visit_Ellipsis = bad_node
3092
3093 blacklist = DetectBadNodes()
3094 blacklist.visit(module)
3095 if blacklist.bad:
3096 fail("Unsupported expression as default value: " + repr(default))
3097
3098 expr = module.body[0].value
3099 # mild hack: explicitly support NULL as a default value
3100 if isinstance(expr, ast.Name) and expr.id == 'NULL':
3101 value = NULL
3102 py_default = 'None'
3103 c_default = "NULL"
3104 elif (isinstance(expr, ast.BinOp) or
3105 (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))):
3106 c_default = kwargs.get("c_default")
3107 if not (isinstance(c_default, str) and c_default):
3108 fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.")
3109 py_default = default
3110 value = unknown
3111 elif isinstance(expr, ast.Attribute):
3112 a = []
3113 n = expr
3114 while isinstance(n, ast.Attribute):
3115 a.append(n.attr)
3116 n = n.value
3117 if not isinstance(n, ast.Name):
3118 fail("Unsupported default value " + repr(default) + " (looked like a Python constant)")
3119 a.append(n.id)
3120 py_default = ".".join(reversed(a))
3121
3122 c_default = kwargs.get("c_default")
3123 if not (isinstance(c_default, str) and c_default):
3124 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3125
3126 try:
3127 value = eval(py_default)
3128 except NameError:
3129 value = unknown
3130 else:
3131 value = ast.literal_eval(expr)
3132 py_default = repr(value)
3133 if isinstance(value, (bool, None.__class__)):
3134 c_default = "Py_" + py_default
3135 elif isinstance(value, str):
Larry Hastings4903e002014-01-18 00:26:16 -08003136 c_default = c_repr(value)
Larry Hastings2a727912014-01-16 11:32:01 -08003137 else:
3138 c_default = py_default
3139
3140 except SyntaxError as e:
3141 fail("Syntax error: " + repr(e.text))
3142 except (ValueError, AttributeError):
3143 value = unknown
Larry Hastings4a55fc52014-01-12 11:09:57 -08003144 c_default = kwargs.get("c_default")
Larry Hastings2a727912014-01-16 11:32:01 -08003145 py_default = default
Larry Hastings4a55fc52014-01-12 11:09:57 -08003146 if not (isinstance(c_default, str) and c_default):
3147 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
3148
Larry Hastings2a727912014-01-16 11:32:01 -08003149 kwargs.setdefault('c_default', c_default)
3150 kwargs.setdefault('py_default', py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003151
Larry Hastings31826802013-10-19 00:09:25 -07003152 dict = legacy_converters if legacy else converters
3153 legacy_str = "legacy " if legacy else ""
3154 if name not in dict:
3155 fail('{} is not a valid {}converter'.format(name, legacy_str))
3156 converter = dict[name](parameter_name, self.function, value, **kwargs)
3157
Larry Hastingsebdcb502013-11-23 14:54:00 -08003158 # special case: if it's the self converter,
3159 # don't actually add it to the parameter list
3160 if isinstance(converter, self_converter):
3161 if self.function.parameters or (self.parameter_state != self.ps_required):
3162 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
3163 if self.function.self_converter:
3164 fail("You can't specify the 'self' parameter more than once.")
3165 self.function.self_converter = converter
3166 self.parameter_state = self.ps_start
3167 return
3168
Larry Hastings31826802013-10-19 00:09:25 -07003169 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
3170 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
Larry Hastingsbebf7352014-01-17 17:47:17 -08003171
3172 if parameter_name in self.function.parameters:
3173 fail("You can't have two parameters named " + repr(parameter_name) + "!")
Larry Hastings31826802013-10-19 00:09:25 -07003174 self.function.parameters[parameter_name] = p
3175
3176 def parse_converter(self, annotation):
3177 if isinstance(annotation, ast.Str):
3178 return annotation.s, True, {}
3179
3180 if isinstance(annotation, ast.Name):
3181 return annotation.id, False, {}
3182
Larry Hastings4a55fc52014-01-12 11:09:57 -08003183 if not isinstance(annotation, ast.Call):
3184 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07003185
3186 name = annotation.func.id
3187 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
3188 return name, False, kwargs
3189
3190 def parse_special_symbol(self, symbol):
3191 if self.parameter_state == self.ps_seen_slash:
3192 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
3193
3194 if symbol == '*':
3195 if self.keyword_only:
3196 fail("Function " + self.function.name + " uses '*' more than once.")
3197 self.keyword_only = True
3198 elif symbol == '[':
3199 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
3200 self.parameter_state = self.ps_left_square_before
3201 elif self.parameter_state in (self.ps_required, self.ps_group_after):
3202 self.parameter_state = self.ps_group_after
3203 else:
3204 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3205 self.group += 1
3206 elif symbol == ']':
3207 if not self.group:
3208 fail("Function " + self.function.name + " has a ] without a matching [.")
3209 if not any(p.group == self.group for p in self.function.parameters.values()):
3210 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
3211 self.group -= 1
3212 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
3213 self.parameter_state = self.ps_group_before
3214 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
3215 self.parameter_state = self.ps_right_square_after
3216 else:
3217 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3218 elif symbol == '/':
3219 # ps_required is allowed here, that allows positional-only without option groups
3220 # to work (and have default values!)
3221 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
3222 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
3223 if self.keyword_only:
3224 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3225 self.parameter_state = self.ps_seen_slash
3226 # fixup preceeding parameters
3227 for p in self.function.parameters.values():
3228 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
3229 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
3230 p.kind = inspect.Parameter.POSITIONAL_ONLY
3231
3232 def state_parameter_docstring_start(self, line):
3233 self.parameter_docstring_indent = len(self.indent.margin)
3234 assert self.indent.depth == 3
3235 return self.next(self.state_parameter_docstring, line)
3236
3237 # every line of the docstring must start with at least F spaces,
3238 # where F > P.
3239 # these F spaces will be stripped.
3240 def state_parameter_docstring(self, line):
3241 stripped = line.strip()
3242 if stripped.startswith('#'):
3243 return
3244
3245 indent = self.indent.measure(line)
3246 if indent < self.parameter_docstring_indent:
3247 self.indent.infer(line)
3248 assert self.indent.depth < 3
3249 if self.indent.depth == 2:
3250 # back to a parameter
3251 return self.next(self.state_parameter, line)
3252 assert self.indent.depth == 1
3253 return self.next(self.state_function_docstring, line)
3254
3255 assert self.function.parameters
3256 last_parameter = next(reversed(list(self.function.parameters.values())))
3257
3258 new_docstring = last_parameter.docstring
3259
3260 if new_docstring:
3261 new_docstring += '\n'
3262 if stripped:
3263 new_docstring += self.indent.dedent(line)
3264
3265 last_parameter.docstring = new_docstring
3266
3267 # the final stanza of the DSL is the docstring.
3268 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07003269 if self.group:
3270 fail("Function " + self.function.name + " has a ] without a matching [.")
3271
3272 stripped = line.strip()
3273 if stripped.startswith('#'):
3274 return
3275
3276 new_docstring = self.function.docstring
3277 if new_docstring:
3278 new_docstring += "\n"
3279 if stripped:
3280 line = self.indent.dedent(line).rstrip()
3281 else:
3282 line = ''
3283 new_docstring += line
3284 self.function.docstring = new_docstring
3285
3286 def format_docstring(self):
3287 f = self.function
3288
3289 add, output = text_accumulator()
3290 parameters = list(f.parameters.values())
3291
3292 ##
3293 ## docstring first line
3294 ##
3295
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003296 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07003297 add('(')
3298
3299 # populate "right_bracket_count" field for every parameter
3300 if parameters:
3301 # for now, the only way Clinic supports positional-only parameters
3302 # is if all of them are positional-only.
3303 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
3304 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
3305 assert all(positional_only_parameters)
3306 for p in parameters:
3307 p.right_bracket_count = abs(p.group)
3308 else:
3309 # don't put any right brackets around non-positional-only parameters, ever.
3310 for p in parameters:
3311 p.right_bracket_count = 0
3312
3313 right_bracket_count = 0
3314
3315 def fix_right_bracket_count(desired):
3316 nonlocal right_bracket_count
3317 s = ''
3318 while right_bracket_count < desired:
3319 s += '['
3320 right_bracket_count += 1
3321 while right_bracket_count > desired:
3322 s += ']'
3323 right_bracket_count -= 1
3324 return s
3325
3326 added_star = False
3327 add_comma = False
3328
3329 for p in parameters:
3330 assert p.name
3331
3332 if p.is_keyword_only() and not added_star:
3333 added_star = True
3334 if add_comma:
3335 add(', ')
3336 add('*')
3337
3338 a = [p.name]
3339 if p.converter.is_optional():
3340 a.append('=')
3341 value = p.converter.default
Larry Hastings2a727912014-01-16 11:32:01 -08003342 a.append(p.converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003343 s = fix_right_bracket_count(p.right_bracket_count)
3344 s += "".join(a)
3345 if add_comma:
3346 add(', ')
3347 add(s)
3348 add_comma = True
3349
3350 add(fix_right_bracket_count(0))
3351 add(')')
3352
Larry Hastings2a727912014-01-16 11:32:01 -08003353 # PEP 8 says:
3354 #
3355 # The Python standard library will not use function annotations
3356 # as that would result in a premature commitment to a particular
3357 # annotation style. Instead, the annotations are left for users
3358 # to discover and experiment with useful annotation styles.
3359 #
3360 # therefore this is commented out:
3361 #
3362 # if f.return_converter.py_default:
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003363 # add(' -> ')
Larry Hastings2a727912014-01-16 11:32:01 -08003364 # add(f.return_converter.py_default)
Larry Hastings31826802013-10-19 00:09:25 -07003365
3366 docstring_first_line = output()
3367
3368 # now fix up the places where the brackets look wrong
3369 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
3370
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003371 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07003372 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003373 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07003374 for p in parameters:
3375 if not p.docstring.strip():
3376 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003377 if spacer_line:
3378 add('\n')
3379 else:
3380 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07003381 add(" ")
3382 add(p.name)
3383 add('\n')
3384 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003385 parameters = output()
3386 if parameters:
3387 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07003388
3389 ##
3390 ## docstring body
3391 ##
3392
3393 docstring = f.docstring.rstrip()
3394 lines = [line.rstrip() for line in docstring.split('\n')]
3395
3396 # Enforce the summary line!
3397 # The first line of a docstring should be a summary of the function.
3398 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
3399 # by itself.
3400 #
3401 # Argument Clinic enforces the following rule:
3402 # * either the docstring is empty,
3403 # * or it must have a summary line.
3404 #
3405 # Guido said Clinic should enforce this:
3406 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
3407
3408 if len(lines) >= 2:
3409 if lines[1]:
3410 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
3411 "Every non-blank function docstring must start with\n" +
3412 "a single line summary followed by an empty line.")
3413 elif len(lines) == 1:
3414 # the docstring is only one line right now--the summary line.
3415 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003416 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07003417 lines.append('')
3418
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003419 parameters_marker_count = len(docstring.split('{parameters}')) - 1
3420 if parameters_marker_count > 1:
3421 fail('You may not specify {parameters} more than once in a docstring!')
3422
3423 if not parameters_marker_count:
3424 # insert after summary line
3425 lines.insert(2, '{parameters}')
3426
3427 # insert at front of docstring
3428 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07003429
3430 docstring = "\n".join(lines)
3431
3432 add(docstring)
3433 docstring = output()
3434
Larry Hastings44e2eaa2013-11-23 15:37:55 -08003435 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07003436 docstring = docstring.rstrip()
3437
3438 return docstring
3439
3440 def state_terminal(self, line):
3441 """
3442 Called when processing the block is done.
3443 """
3444 assert not line
3445
3446 if not self.function:
3447 return
3448
Larry Hastings6d2ea212014-01-05 02:50:45 -08003449 if not self.function.self_converter:
3450 self.function.self_converter = self_converter("self", self.function)
3451
Larry Hastings31826802013-10-19 00:09:25 -07003452 if self.keyword_only:
3453 values = self.function.parameters.values()
3454 if not values:
3455 no_parameter_after_star = True
3456 else:
3457 last_parameter = next(reversed(list(values)))
3458 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
3459 if no_parameter_after_star:
3460 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
3461
3462 # remove trailing whitespace from all parameter docstrings
3463 for name, value in self.function.parameters.items():
3464 if not value:
3465 continue
3466 value.docstring = value.docstring.rstrip()
3467
3468 self.function.docstring = self.format_docstring()
3469
3470
3471# maps strings to callables.
3472# the callable should return an object
3473# that implements the clinic parser
3474# interface (__init__ and parse).
3475#
3476# example parsers:
3477# "clinic", handles the Clinic DSL
3478# "python", handles running Python code
3479#
3480parsers = {'clinic' : DSLParser, 'python': PythonParser}
3481
3482
3483clinic = None
3484
3485
3486def main(argv):
3487 import sys
3488
3489 if sys.version_info.major < 3 or sys.version_info.minor < 3:
3490 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
3491
3492 import argparse
3493 cmdline = argparse.ArgumentParser()
3494 cmdline.add_argument("-f", "--force", action='store_true')
3495 cmdline.add_argument("-o", "--output", type=str)
3496 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003497 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07003498 cmdline.add_argument("filename", type=str, nargs="*")
3499 ns = cmdline.parse_args(argv)
3500
3501 if ns.converters:
3502 if ns.filename:
3503 print("Usage error: can't specify --converters and a filename at the same time.")
3504 print()
3505 cmdline.print_usage()
3506 sys.exit(-1)
3507 converters = []
3508 return_converters = []
3509 ignored = set("""
3510 add_c_converter
3511 add_c_return_converter
3512 add_default_legacy_c_converter
3513 add_legacy_c_converter
3514 """.strip().split())
3515 module = globals()
3516 for name in module:
3517 for suffix, ids in (
3518 ("_return_converter", return_converters),
3519 ("_converter", converters),
3520 ):
3521 if name in ignored:
3522 continue
3523 if name.endswith(suffix):
3524 ids.append((name, name[:-len(suffix)]))
3525 break
3526 print()
3527
3528 print("Legacy converters:")
3529 legacy = sorted(legacy_converters)
3530 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
3531 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
3532 print()
3533
3534 for title, attribute, ids in (
3535 ("Converters", 'converter_init', converters),
3536 ("Return converters", 'return_converter_init', return_converters),
3537 ):
3538 print(title + ":")
3539 longest = -1
3540 for name, short_name in ids:
3541 longest = max(longest, len(short_name))
3542 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
3543 cls = module[name]
3544 callable = getattr(cls, attribute, None)
3545 if not callable:
3546 continue
3547 signature = inspect.signature(callable)
3548 parameters = []
3549 for parameter_name, parameter in signature.parameters.items():
3550 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
3551 if parameter.default != inspect.Parameter.empty:
3552 s = '{}={!r}'.format(parameter_name, parameter.default)
3553 else:
3554 s = parameter_name
3555 parameters.append(s)
3556 print(' {}({})'.format(short_name, ', '.join(parameters)))
Larry Hastings31826802013-10-19 00:09:25 -07003557 print()
Larry Hastings2a727912014-01-16 11:32:01 -08003558 print("All converters also accept (c_default=None, py_default=None, annotation=None).")
3559 print("All return converters also accept (py_default=None).")
Larry Hastings31826802013-10-19 00:09:25 -07003560 sys.exit(0)
3561
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003562 if ns.make:
3563 if ns.output or ns.filename:
3564 print("Usage error: can't use -o or filenames with --make.")
3565 print()
3566 cmdline.print_usage()
3567 sys.exit(-1)
3568 for root, dirs, files in os.walk('.'):
3569 for rcs_dir in ('.svn', '.git', '.hg'):
3570 if rcs_dir in dirs:
3571 dirs.remove(rcs_dir)
3572 for filename in files:
3573 if not filename.endswith('.c'):
3574 continue
3575 path = os.path.join(root, filename)
3576 parse_file(path, verify=not ns.force)
3577 return
3578
Larry Hastings31826802013-10-19 00:09:25 -07003579 if not ns.filename:
3580 cmdline.print_usage()
3581 sys.exit(-1)
3582
3583 if ns.output and len(ns.filename) > 1:
3584 print("Usage error: can't use -o with multiple filenames.")
3585 print()
3586 cmdline.print_usage()
3587 sys.exit(-1)
3588
3589 for filename in ns.filename:
3590 parse_file(filename, output=ns.output, verify=not ns.force)
3591
3592
3593if __name__ == "__main__":
3594 sys.exit(main(sys.argv[1:]))