blob: 23e0b9393344d183486232cfa6ca7c1892386738 [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
19import re
20import shlex
21import sys
22import tempfile
23import textwrap
Georg Brandlaabebde2014-01-16 06:53:54 +010024import traceback
Larry Hastings31826802013-10-19 00:09:25 -070025
Larry Hastings31826802013-10-19 00:09:25 -070026# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070027#
28# soon:
29#
30# * allow mixing any two of {positional-only, positional-or-keyword,
31# keyword-only}
32# * dict constructor uses positional-only and keyword-only
33# * max and min use positional only with an optional group
34# and keyword-only
35#
Larry Hastings31826802013-10-19 00:09:25 -070036
Larry Hastingsebdcb502013-11-23 14:54:00 -080037version = '1'
38
Larry Hastings31826802013-10-19 00:09:25 -070039_empty = inspect._empty
40_void = inspect._void
41
Larry Hastings4a55fc52014-01-12 11:09:57 -080042NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070043
44class Unspecified:
45 def __repr__(self):
46 return '<Unspecified>'
47
48unspecified = Unspecified()
49
50
51class Null:
52 def __repr__(self):
53 return '<Null>'
54
55NULL = Null()
56
57
58def _text_accumulator():
59 text = []
60 def output():
61 s = ''.join(text)
62 text.clear()
63 return s
64 return text, text.append, output
65
66
67def text_accumulator():
68 """
69 Creates a simple text accumulator / joiner.
70
71 Returns a pair of callables:
72 append, output
73 "append" appends a string to the accumulator.
74 "output" returns the contents of the accumulator
75 joined together (''.join(accumulator)) and
76 empties the accumulator.
77 """
78 text, append, output = _text_accumulator()
79 return append, output
80
81
82def fail(*args, filename=None, line_number=None):
83 joined = " ".join([str(a) for a in args])
84 add, output = text_accumulator()
85 add("Error")
86 if clinic:
87 if filename is None:
88 filename = clinic.filename
89 if clinic.block_parser and (line_number is None):
90 line_number = clinic.block_parser.line_number
91 if filename is not None:
92 add(' in file "' + filename + '"')
93 if line_number is not None:
94 add(" on line " + str(line_number))
95 add(':\n')
96 add(joined)
97 print(output())
98 sys.exit(-1)
99
100
101
102def quoted_for_c_string(s):
103 for old, new in (
104 ('"', '\\"'),
105 ("'", "\\'"),
106 ):
107 s = s.replace(old, new)
108 return s
109
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700110is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
111
112def is_legal_py_identifier(s):
113 return all(is_legal_c_identifier(field) for field in s.split('.'))
114
Larry Hastings8666e652014-01-12 14:12:59 -0800115# though it's called c_keywords, really it's a list of parameter names
116# that are okay in Python but aren't a good idea in C. so if they're used
117# Argument Clinic will add "_value" to the end of the name in C.
118# (We added "args", "type", "module", "self", "cls", and "null"
119# just to be safe, even though they're not C keywords.)
Larry Hastings31826802013-10-19 00:09:25 -0700120c_keywords = set("""
Larry Hastings8666e652014-01-12 14:12:59 -0800121args asm auto break case char cls const continue default do double
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800122else enum extern float for goto if inline int long module null
123register return self short signed sizeof static struct switch
Larry Hastings8666e652014-01-12 14:12:59 -0800124type typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700125""".strip().split())
126
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700127def ensure_legal_c_identifier(s):
128 # for now, just complain if what we're given isn't legal
129 if not is_legal_c_identifier(s):
130 fail("Illegal C identifier: {}".format(s))
131 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700132 if s in c_keywords:
133 return s + "_value"
134 return s
135
136def rstrip_lines(s):
137 text, add, output = _text_accumulator()
138 for line in s.split('\n'):
139 add(line.rstrip())
140 add('\n')
141 text.pop()
142 return output()
143
144def linear_format(s, **kwargs):
145 """
146 Perform str.format-like substitution, except:
147 * The strings substituted must be on lines by
148 themselves. (This line is the "source line".)
149 * If the substitution text is empty, the source line
150 is removed in the output.
151 * If the substitution text is not empty:
152 * Each line of the substituted text is indented
153 by the indent of the source line.
154 * A newline will be added to the end.
155 """
156
157 add, output = text_accumulator()
158 for line in s.split('\n'):
159 indent, curly, trailing = line.partition('{')
160 if not curly:
161 add(line)
162 add('\n')
163 continue
164
165 name, curl, trailing = trailing.partition('}')
166 if not curly or name not in kwargs:
167 add(line)
168 add('\n')
169 continue
170
171 if trailing:
172 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
173 if indent.strip():
174 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
175
176 value = kwargs[name]
177 if not value:
178 continue
179
180 value = textwrap.indent(rstrip_lines(value), indent)
181 add(value)
182 add('\n')
183
184 return output()[:-1]
185
Larry Hastingsebdcb502013-11-23 14:54:00 -0800186def version_splitter(s):
187 """Splits a version string into a tuple of integers.
188
189 The following ASCII characters are allowed, and employ
190 the following conversions:
191 a -> -3
192 b -> -2
193 c -> -1
194 (This permits Python-style version strings such as "1.4b3".)
195 """
196 version = []
197 accumulator = []
198 def flush():
199 if not accumulator:
200 raise ValueError('Malformed version string: ' + repr(s))
201 version.append(int(''.join(accumulator)))
202 accumulator.clear()
203
204 for c in s:
205 if c.isdigit():
206 accumulator.append(c)
207 elif c == '.':
208 flush()
209 elif c in 'abc':
210 flush()
211 version.append('abc'.index(c) - 3)
212 else:
213 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
214 flush()
215 return tuple(version)
216
217def version_comparitor(version1, version2):
218 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
219 for i, (a, b) in enumerate(iterator):
220 if a < b:
221 return -1
222 if a > b:
223 return 1
224 return 0
225
Larry Hastings31826802013-10-19 00:09:25 -0700226
227class CRenderData:
228 def __init__(self):
229
230 # The C statements to declare variables.
231 # Should be full lines with \n eol characters.
232 self.declarations = []
233
234 # The C statements required to initialize the variables before the parse call.
235 # Should be full lines with \n eol characters.
236 self.initializers = []
237
238 # The entries for the "keywords" array for PyArg_ParseTuple.
239 # Should be individual strings representing the names.
240 self.keywords = []
241
242 # The "format units" for PyArg_ParseTuple.
243 # Should be individual strings that will get
244 self.format_units = []
245
246 # The varargs arguments for PyArg_ParseTuple.
247 self.parse_arguments = []
248
249 # The parameter declarations for the impl function.
250 self.impl_parameters = []
251
252 # The arguments to the impl function at the time it's called.
253 self.impl_arguments = []
254
255 # For return converters: the name of the variable that
256 # should receive the value returned by the impl.
257 self.return_value = "return_value"
258
259 # For return converters: the code to convert the return
260 # value from the parse function. This is also where
261 # you should check the _return_value for errors, and
262 # "goto exit" if there are any.
263 self.return_conversion = []
264
265 # The C statements required to clean up after the impl call.
266 self.cleanup = []
267
268
269class Language(metaclass=abc.ABCMeta):
270
271 start_line = ""
272 body_prefix = ""
273 stop_line = ""
274 checksum_line = ""
275
276 @abc.abstractmethod
277 def render(self, block):
278 pass
279
280 def validate(self):
281 def assert_only_one(field, token='dsl_name'):
282 line = getattr(self, field)
283 token = '{' + token + '}'
284 if len(line.split(token)) != 2:
285 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
286 assert_only_one('start_line')
287 assert_only_one('stop_line')
288 assert_only_one('checksum_line')
289 assert_only_one('checksum_line', 'checksum')
290
291 if len(self.body_prefix.split('{dsl_name}')) >= 3:
292 fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
293
294
295
296class PythonLanguage(Language):
297
298 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800299 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700300 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800301 stop_line = "#[{dsl_name} start generated code]*/"
302 checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700303
304
305def permute_left_option_groups(l):
306 """
307 Given [1, 2, 3], should yield:
308 ()
309 (3,)
310 (2, 3)
311 (1, 2, 3)
312 """
313 yield tuple()
314 accumulator = []
315 for group in reversed(l):
316 accumulator = list(group) + accumulator
317 yield tuple(accumulator)
318
319
320def permute_right_option_groups(l):
321 """
322 Given [1, 2, 3], should yield:
323 ()
324 (1,)
325 (1, 2)
326 (1, 2, 3)
327 """
328 yield tuple()
329 accumulator = []
330 for group in l:
331 accumulator.extend(group)
332 yield tuple(accumulator)
333
334
335def permute_optional_groups(left, required, right):
336 """
337 Generator function that computes the set of acceptable
338 argument lists for the provided iterables of
339 argument groups. (Actually it generates a tuple of tuples.)
340
341 Algorithm: prefer left options over right options.
342
343 If required is empty, left must also be empty.
344 """
345 required = tuple(required)
346 result = []
347
348 if not required:
349 assert not left
350
351 accumulator = []
352 counts = set()
353 for r in permute_right_option_groups(right):
354 for l in permute_left_option_groups(left):
355 t = l + required + r
356 if len(t) in counts:
357 continue
358 counts.add(len(t))
359 accumulator.append(t)
360
361 accumulator.sort(key=len)
362 return tuple(accumulator)
363
364
365class CLanguage(Language):
366
Larry Hastings61272b72014-01-07 12:41:53 -0800367 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700368 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800369 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700370 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800371 stop_line = "[{dsl_name} start generated code]*/"
372 checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700373
374 def render(self, signatures):
375 function = None
376 for o in signatures:
377 if isinstance(o, Function):
378 if function:
379 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
380 function = o
381 return self.render_function(function)
382
383 def docstring_for_c_string(self, f):
384 text, add, output = _text_accumulator()
385 # turn docstring into a properly quoted C string
386 for line in f.docstring.split('\n'):
387 add('"')
388 add(quoted_for_c_string(line))
389 add('\\n"\n')
390
391 text.pop()
392 add('"')
393 return ''.join(text)
394
395 impl_prototype_template = "{c_basename}_impl({impl_parameters})"
396
397 @staticmethod
398 def template_base(*args):
Larry Hastings8666e652014-01-12 14:12:59 -0800399 # HACK suppress methoddef define for METHOD_NEW and METHOD_INIT
400 base = """
Larry Hastings31826802013-10-19 00:09:25 -0700401PyDoc_STRVAR({c_basename}__doc__,
402{docstring});
Larry Hastings8666e652014-01-12 14:12:59 -0800403"""
Larry Hastings31826802013-10-19 00:09:25 -0700404
Larry Hastings8666e652014-01-12 14:12:59 -0800405 if args[-1] == None:
406 return base
407
408 flags = '|'.join(f for f in args if f)
409 return base + """
Larry Hastings31826802013-10-19 00:09:25 -0700410#define {methoddef_name} \\
Larry Hastingsebdcb502013-11-23 14:54:00 -0800411 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
412""".replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700413
Larry Hastingsebdcb502013-11-23 14:54:00 -0800414 def meth_noargs_template(self, methoddef_flags=""):
415 return self.template_base("METH_NOARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700416static {impl_return_type}
417{impl_prototype};
418
419static PyObject *
Larry Hastings3cceb382014-01-04 11:09:09 -0800420{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
Larry Hastings31826802013-10-19 00:09:25 -0700421{{
422 PyObject *return_value = NULL;
423 {declarations}
424 {initializers}
425
426 {return_value} = {c_basename}_impl({impl_arguments});
427 {return_conversion}
428
429{exit_label}
430 {cleanup}
431 return return_value;
432}}
433
434static {impl_return_type}
435{impl_prototype}
436"""
437
Larry Hastingsebdcb502013-11-23 14:54:00 -0800438 def meth_o_template(self, methoddef_flags=""):
439 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700440static PyObject *
441{c_basename}({impl_parameters})
442"""
443
Larry Hastingsebdcb502013-11-23 14:54:00 -0800444 def meth_o_return_converter_template(self, methoddef_flags=""):
445 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700446static {impl_return_type}
447{impl_prototype};
448
449static PyObject *
450{c_basename}({impl_parameters})
451{{
452 PyObject *return_value = NULL;
453 {declarations}
454 {initializers}
455 _return_value = {c_basename}_impl({impl_arguments});
456 {return_conversion}
457
458{exit_label}
459 {cleanup}
460 return return_value;
461}}
462
463static {impl_return_type}
464{impl_prototype}
465"""
466
Larry Hastingsebdcb502013-11-23 14:54:00 -0800467 def option_group_template(self, methoddef_flags=""):
468 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700469static {impl_return_type}
470{impl_prototype};
471
472static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800473{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700474{{
475 PyObject *return_value = NULL;
476 {declarations}
477 {initializers}
478
479 {option_group_parsing}
480 {return_value} = {c_basename}_impl({impl_arguments});
481 {return_conversion}
482
483{exit_label}
484 {cleanup}
485 return return_value;
486}}
487
488static {impl_return_type}
489{impl_prototype}
490"""
491
Larry Hastingsebdcb502013-11-23 14:54:00 -0800492 def keywords_template(self, methoddef_flags=""):
493 return self.template_base("METH_VARARGS|METH_KEYWORDS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700494static {impl_return_type}
495{impl_prototype};
496
497static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800498{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
Larry Hastings31826802013-10-19 00:09:25 -0700499{{
500 PyObject *return_value = NULL;
501 static char *_keywords[] = {{{keywords}, NULL}};
502 {declarations}
503 {initializers}
504
505 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
506 "{format_units}:{name}", _keywords,
507 {parse_arguments}))
508 goto exit;
509 {return_value} = {c_basename}_impl({impl_arguments});
510 {return_conversion}
511
512{exit_label}
513 {cleanup}
514 return return_value;
515}}
516
517static {impl_return_type}
518{impl_prototype}
519"""
520
Larry Hastingsebdcb502013-11-23 14:54:00 -0800521 def positional_only_template(self, methoddef_flags=""):
522 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700523static {impl_return_type}
524{impl_prototype};
525
526static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800527{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700528{{
529 PyObject *return_value = NULL;
530 {declarations}
531 {initializers}
532
533 if (!PyArg_ParseTuple(args,
534 "{format_units}:{name}",
535 {parse_arguments}))
536 goto exit;
537 {return_value} = {c_basename}_impl({impl_arguments});
538 {return_conversion}
539
540{exit_label}
541 {cleanup}
542 return return_value;
543}}
544
545static {impl_return_type}
546{impl_prototype}
547"""
548
549 @staticmethod
550 def group_to_variable_name(group):
551 adjective = "left_" if group < 0 else "right_"
552 return "group_" + adjective + str(abs(group))
553
554 def render_option_group_parsing(self, f, template_dict):
555 # positional only, grouped, optional arguments!
556 # can be optional on the left or right.
557 # here's an example:
558 #
559 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
560 #
561 # Here group D are required, and all other groups are optional.
562 # (Group D's "group" is actually None.)
563 # We can figure out which sets of arguments we have based on
564 # how many arguments are in the tuple.
565 #
566 # Note that you need to count up on both sides. For example,
567 # you could have groups C+D, or C+D+E, or C+D+E+F.
568 #
569 # What if the number of arguments leads us to an ambiguous result?
570 # Clinic prefers groups on the left. So in the above example,
571 # five arguments would map to B+C, not C+D.
572
573 add, output = text_accumulator()
574 parameters = list(f.parameters.values())
575
576 groups = []
577 group = None
578 left = []
579 right = []
580 required = []
581 last = unspecified
582
583 for p in parameters:
584 group_id = p.group
585 if group_id != last:
586 last = group_id
587 group = []
588 if group_id < 0:
589 left.append(group)
590 elif group_id == 0:
591 group = required
592 else:
593 right.append(group)
594 group.append(p)
595
596 count_min = sys.maxsize
597 count_max = -1
598
599 add("switch (PyTuple_Size(args)) {{\n")
600 for subset in permute_optional_groups(left, required, right):
601 count = len(subset)
602 count_min = min(count_min, count)
603 count_max = max(count_max, count)
604
Larry Hastings583baa82014-01-12 08:49:30 -0800605 if count == 0:
606 add(""" case 0:
607 break;
608""")
609 continue
610
Larry Hastings31826802013-10-19 00:09:25 -0700611 group_ids = {p.group for p in subset} # eliminate duplicates
612 d = {}
613 d['count'] = count
614 d['name'] = f.name
615 d['groups'] = sorted(group_ids)
616 d['format_units'] = "".join(p.converter.format_unit for p in subset)
617
618 parse_arguments = []
619 for p in subset:
620 p.converter.parse_argument(parse_arguments)
621 d['parse_arguments'] = ", ".join(parse_arguments)
622
623 group_ids.discard(0)
624 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
625 lines = "\n".join(lines)
626
627 s = """
628 case {count}:
629 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
630 return NULL;
631 {group_booleans}
632 break;
633"""[1:]
634 s = linear_format(s, group_booleans=lines)
635 s = s.format_map(d)
636 add(s)
637
638 add(" default:\n")
639 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
640 add(s.format(f.full_name, count_min, count_max))
641 add(' return NULL;\n')
642 add("}}")
643 template_dict['option_group_parsing'] = output()
644
645 def render_function(self, f):
646 if not f:
647 return ""
648
649 add, output = text_accumulator()
650 data = CRenderData()
651
Larry Hastings31826802013-10-19 00:09:25 -0700652 parameters = list(f.parameters.values())
653 converters = [p.converter for p in parameters]
654
655 template_dict = {}
656
657 full_name = f.full_name
658 template_dict['full_name'] = full_name
659
660 name = full_name.rpartition('.')[2]
661 template_dict['name'] = name
662
Larry Hastings8666e652014-01-12 14:12:59 -0800663 if f.c_basename:
664 c_basename = f.c_basename
665 else:
666 fields = full_name.split(".")
667 if fields[-1] == '__new__':
668 fields.pop()
669 c_basename = "_".join(fields)
Larry Hastings31826802013-10-19 00:09:25 -0700670 template_dict['c_basename'] = c_basename
671
672 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
673 template_dict['methoddef_name'] = methoddef_name
674
675 template_dict['docstring'] = self.docstring_for_c_string(f)
676
Larry Hastings31826802013-10-19 00:09:25 -0700677 positional = has_option_groups = False
678
679 if parameters:
680 last_group = 0
681
682 for p in parameters:
683 c = p.converter
684
685 # insert group variable
686 group = p.group
687 if last_group != group:
688 last_group = group
689 if group:
690 group_name = self.group_to_variable_name(group)
691 data.impl_arguments.append(group_name)
692 data.declarations.append("int " + group_name + " = 0;")
693 data.impl_parameters.append("int " + group_name)
694 has_option_groups = True
695 c.render(p, data)
696
697 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
Larry Hastings4a55fc52014-01-12 11:09:57 -0800698 if has_option_groups and (not positional):
699 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
Larry Hastings31826802013-10-19 00:09:25 -0700700
Larry Hastingsebdcb502013-11-23 14:54:00 -0800701 # now insert our "self" (or whatever) parameters
702 # (we deliberately don't call render on self converters)
703 stock_self = self_converter('self', f)
704 template_dict['self_name'] = stock_self.name
705 template_dict['self_type'] = stock_self.type
706 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
707 if f.self_converter.type != stock_self.type:
708 self_cast = '(' + f.self_converter.type + ')'
709 else:
710 self_cast = ''
711 data.impl_arguments.insert(0, self_cast + stock_self.name)
712
Larry Hastings31826802013-10-19 00:09:25 -0700713 f.return_converter.render(f, data)
714 template_dict['impl_return_type'] = f.return_converter.type
715
716 template_dict['declarations'] = "\n".join(data.declarations)
717 template_dict['initializers'] = "\n\n".join(data.initializers)
718 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
719 template_dict['format_units'] = ''.join(data.format_units)
720 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
721 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
722 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
723 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
724 template_dict['cleanup'] = "".join(data.cleanup)
725 template_dict['return_value'] = data.return_value
726
727 template_dict['impl_prototype'] = self.impl_prototype_template.format_map(template_dict)
728
729 default_return_converter = (not f.return_converter or
730 f.return_converter.type == 'PyObject *')
731
732 if not parameters:
Larry Hastings3cceb382014-01-04 11:09:09 -0800733 template = self.meth_noargs_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700734 elif (len(parameters) == 1 and
735 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
736 not converters[0].is_optional() and
737 isinstance(converters[0], object_converter) and
738 converters[0].format_unit == 'O'):
739 if default_return_converter:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800740 template = self.meth_o_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700741 else:
742 # HACK
743 # we're using "impl_parameters" for the
744 # non-impl function, because that works
745 # better for METH_O. but that means we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800746 # must supress actually declaring the
Larry Hastings31826802013-10-19 00:09:25 -0700747 # impl's parameters as variables in the
748 # non-impl. but since it's METH_O, we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800749 # only have one anyway, so
750 # we don't have any problem finding it.
Larry Hastings31826802013-10-19 00:09:25 -0700751 declarations_copy = list(data.declarations)
752 before, pyobject, after = declarations_copy[0].partition('PyObject *')
753 assert not before, "hack failed, see comment"
754 assert pyobject, "hack failed, see comment"
755 assert after and after[0].isalpha(), "hack failed, see comment"
756 del declarations_copy[0]
757 template_dict['declarations'] = "\n".join(declarations_copy)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800758 template = self.meth_o_return_converter_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700759 elif has_option_groups:
760 self.render_option_group_parsing(f, template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800761 template = self.option_group_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700762 template = linear_format(template,
763 option_group_parsing=template_dict['option_group_parsing'])
764 elif positional:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800765 template = self.positional_only_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700766 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800767 template = self.keywords_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700768
769 template = linear_format(template,
770 declarations=template_dict['declarations'],
771 return_conversion=template_dict['return_conversion'],
772 initializers=template_dict['initializers'],
773 cleanup=template_dict['cleanup'],
774 )
775
776 # Only generate the "exit:" label
777 # if we have any gotos
778 need_exit_label = "goto exit;" in template
779 template = linear_format(template,
780 exit_label="exit:" if need_exit_label else ''
781 )
782
783 return template.format_map(template_dict)
784
785
786@contextlib.contextmanager
787def OverrideStdioWith(stdout):
788 saved_stdout = sys.stdout
789 sys.stdout = stdout
790 try:
791 yield
792 finally:
793 assert sys.stdout is stdout
794 sys.stdout = saved_stdout
795
796
797def create_regex(before, after):
798 """Create an re object for matching marker lines."""
799 pattern = r'^{}(\w+){}$'
800 return re.compile(pattern.format(re.escape(before), re.escape(after)))
801
802
803class Block:
804 r"""
805 Represents a single block of text embedded in
806 another file. If dsl_name is None, the block represents
807 verbatim text, raw original text from the file, in
808 which case "input" will be the only non-false member.
809 If dsl_name is not None, the block represents a Clinic
810 block.
811
812 input is always str, with embedded \n characters.
813 input represents the original text from the file;
814 if it's a Clinic block, it is the original text with
815 the body_prefix and redundant leading whitespace removed.
816
817 dsl_name is either str or None. If str, it's the text
818 found on the start line of the block between the square
819 brackets.
820
821 signatures is either list or None. If it's a list,
822 it may only contain clinic.Module, clinic.Class, and
823 clinic.Function objects. At the moment it should
824 contain at most one of each.
825
826 output is either str or None. If str, it's the output
827 from this block, with embedded '\n' characters.
828
829 indent is either str or None. It's the leading whitespace
830 that was found on every line of input. (If body_prefix is
831 not empty, this is the indent *after* removing the
832 body_prefix.)
833
834 preindent is either str or None. It's the whitespace that
835 was found in front of every line of input *before* the
836 "body_prefix" (see the Language object). If body_prefix
837 is empty, preindent must always be empty too.
838
839 To illustrate indent and preindent: Assume that '_'
840 represents whitespace. If the block processed was in a
841 Python file, and looked like this:
842 ____#/*[python]
843 ____#__for a in range(20):
844 ____#____print(a)
845 ____#[python]*/
846 "preindent" would be "____" and "indent" would be "__".
847
848 """
849 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
850 assert isinstance(input, str)
851 self.input = input
852 self.dsl_name = dsl_name
853 self.signatures = signatures or []
854 self.output = output
855 self.indent = indent
856 self.preindent = preindent
857
858
859class BlockParser:
860 """
861 Block-oriented parser for Argument Clinic.
862 Iterator, yields Block objects.
863 """
864
865 def __init__(self, input, language, *, verify=True):
866 """
867 "input" should be a str object
868 with embedded \n characters.
869
870 "language" should be a Language object.
871 """
872 language.validate()
873
874 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
875 self.block_start_line_number = self.line_number = 0
876
877 self.language = language
878 before, _, after = language.start_line.partition('{dsl_name}')
879 assert _ == '{dsl_name}'
880 self.start_re = create_regex(before, after)
881 self.verify = verify
882 self.last_checksum_re = None
883 self.last_dsl_name = None
884 self.dsl_name = None
885
886 def __iter__(self):
887 return self
888
889 def __next__(self):
890 if not self.input:
891 raise StopIteration
892
893 if self.dsl_name:
894 return_value = self.parse_clinic_block(self.dsl_name)
895 self.dsl_name = None
896 return return_value
897 return self.parse_verbatim_block()
898
899 def is_start_line(self, line):
900 match = self.start_re.match(line.lstrip())
901 return match.group(1) if match else None
902
903 def _line(self):
904 self.line_number += 1
905 return self.input.pop()
906
907 def parse_verbatim_block(self):
908 add, output = text_accumulator()
909 self.block_start_line_number = self.line_number
910
911 while self.input:
912 line = self._line()
913 dsl_name = self.is_start_line(line)
914 if dsl_name:
915 self.dsl_name = dsl_name
916 break
917 add(line)
918
919 return Block(output())
920
921 def parse_clinic_block(self, dsl_name):
922 input_add, input_output = text_accumulator()
923 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -0800924 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -0700925 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
926
Larry Hastings90261132014-01-07 12:21:08 -0800927 def is_stop_line(line):
928 # make sure to recognize stop line even if it
929 # doesn't end with EOL (it could be the very end of the file)
930 if not line.startswith(stop_line):
931 return False
932 remainder = line[len(stop_line):]
933 return (not remainder) or remainder.isspace()
934
Larry Hastings31826802013-10-19 00:09:25 -0700935 # consume body of program
936 while self.input:
937 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -0800938 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -0700939 break
940 if body_prefix:
941 line = line.lstrip()
942 assert line.startswith(body_prefix)
943 line = line[len(body_prefix):]
944 input_add(line)
945
946 # consume output and checksum line, if present.
947 if self.last_dsl_name == dsl_name:
948 checksum_re = self.last_checksum_re
949 else:
950 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
951 assert _ == '{checksum}'
952 checksum_re = create_regex(before, after)
953 self.last_dsl_name = dsl_name
954 self.last_checksum_re = checksum_re
955
956 # scan forward for checksum line
957 output_add, output_output = text_accumulator()
958 checksum = None
959 while self.input:
960 line = self._line()
961 match = checksum_re.match(line.lstrip())
962 checksum = match.group(1) if match else None
963 if checksum:
964 break
965 output_add(line)
966 if self.is_start_line(line):
967 break
968
Larry Hastingsef3b1fb2013-10-22 23:26:23 -0700969 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -0700970 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -0700971 if self.verify:
972 computed = compute_checksum(output)
973 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +0100974 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
975 "Suggested fix: remove all generated code including "
976 "the end marker, or use the '-f' option."
977 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -0700978 else:
979 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -0800980 output_lines = output.splitlines(keepends=True)
981 self.line_number -= len(output_lines)
982 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -0700983 output = None
984
985 return Block(input_output(), dsl_name, output=output)
986
987
988class BlockPrinter:
989
990 def __init__(self, language, f=None):
991 self.language = language
992 self.f = f or io.StringIO()
993
994 def print_block(self, block):
995 input = block.input
996 output = block.output
997 dsl_name = block.dsl_name
998 write = self.f.write
999
Larry Hastings31826802013-10-19 00:09:25 -07001000 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1001
1002 if not dsl_name:
1003 write(input)
1004 return
1005
1006 write(self.language.start_line.format(dsl_name=dsl_name))
1007 write("\n")
1008
1009 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1010 if not body_prefix:
1011 write(input)
1012 else:
1013 for line in input.split('\n'):
1014 write(body_prefix)
1015 write(line)
1016 write("\n")
1017
1018 write(self.language.stop_line.format(dsl_name=dsl_name))
1019 write("\n")
1020
1021 output = block.output
1022 if output:
1023 write(output)
1024 if not output.endswith('\n'):
1025 write('\n')
1026
1027 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
1028 write("\n")
1029
1030
1031# maps strings to Language objects.
1032# "languages" maps the name of the language ("C", "Python").
1033# "extensions" maps the file extension ("c", "py").
1034languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001035extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1036extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001037
1038
1039# maps strings to callables.
1040# these callables must be of the form:
1041# def foo(name, default, *, ...)
1042# The callable may have any number of keyword-only parameters.
1043# The callable must return a CConverter object.
1044# The callable should not call builtins.print.
1045converters = {}
1046
1047# maps strings to callables.
1048# these callables follow the same rules as those for "converters" above.
1049# note however that they will never be called with keyword-only parameters.
1050legacy_converters = {}
1051
1052
1053# maps strings to callables.
1054# these callables must be of the form:
1055# def foo(*, ...)
1056# The callable may have any number of keyword-only parameters.
1057# The callable must return a CConverter object.
1058# The callable should not call builtins.print.
1059return_converters = {}
1060
1061class Clinic:
1062 def __init__(self, language, printer=None, *, verify=True, filename=None):
1063 # maps strings to Parser objects.
1064 # (instantiated from the "parsers" global.)
1065 self.parsers = {}
1066 self.language = language
1067 self.printer = printer or BlockPrinter(language)
1068 self.verify = verify
1069 self.filename = filename
1070 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001071 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -07001072
1073 global clinic
1074 clinic = self
1075
1076 def parse(self, input):
1077 printer = self.printer
1078 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1079 for block in self.block_parser:
1080 dsl_name = block.dsl_name
1081 if dsl_name:
1082 if dsl_name not in self.parsers:
1083 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1084 self.parsers[dsl_name] = parsers[dsl_name](self)
1085 parser = self.parsers[dsl_name]
Georg Brandlaabebde2014-01-16 06:53:54 +01001086 try:
1087 parser.parse(block)
1088 except Exception:
1089 fail('Exception raised during parsing:\n' +
1090 traceback.format_exc().rstrip())
Larry Hastings31826802013-10-19 00:09:25 -07001091 printer.print_block(block)
1092 return printer.f.getvalue()
1093
1094 def _module_and_class(self, fields):
1095 """
1096 fields should be an iterable of field names.
1097 returns a tuple of (module, class).
1098 the module object could actually be self (a clinic object).
1099 this function is only ever used to find the parent of where
1100 a new class/module should go.
1101 """
1102 in_classes = False
1103 parent = module = self
1104 cls = None
1105 so_far = []
1106
1107 for field in fields:
1108 so_far.append(field)
1109 if not in_classes:
1110 child = parent.modules.get(field)
1111 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001112 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001113 continue
1114 in_classes = True
1115 if not hasattr(parent, 'classes'):
1116 return module, cls
1117 child = parent.classes.get(field)
1118 if not child:
1119 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1120 cls = parent = child
1121
1122 return module, cls
1123
1124
1125def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1126 extension = os.path.splitext(filename)[1][1:]
1127 if not extension:
1128 fail("Can't extract file type for file " + repr(filename))
1129
1130 try:
1131 language = extensions[extension]()
1132 except KeyError:
1133 fail("Can't identify file type for file " + repr(filename))
1134
1135 clinic = Clinic(language, verify=verify, filename=filename)
1136
1137 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001138 raw = f.read()
1139
1140 cooked = clinic.parse(raw)
1141 if cooked == raw:
1142 return
Larry Hastings31826802013-10-19 00:09:25 -07001143
1144 directory = os.path.dirname(filename) or '.'
1145
1146 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001147 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001148 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1149 with open(tmpfilename, "wb") as f:
1150 f.write(bytes)
1151 os.replace(tmpfilename, output or filename)
1152
1153
1154def compute_checksum(input):
1155 input = input or ''
1156 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1157
1158
1159
1160
1161class PythonParser:
1162 def __init__(self, clinic):
1163 pass
1164
1165 def parse(self, block):
1166 s = io.StringIO()
1167 with OverrideStdioWith(s):
1168 exec(block.input)
1169 block.output = s.getvalue()
1170
1171
1172class Module:
1173 def __init__(self, name, module=None):
1174 self.name = name
1175 self.module = self.parent = module
1176
1177 self.modules = collections.OrderedDict()
1178 self.classes = collections.OrderedDict()
1179 self.functions = []
1180
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001181 def __repr__(self):
1182 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1183
Larry Hastings31826802013-10-19 00:09:25 -07001184class Class:
1185 def __init__(self, name, module=None, cls=None):
1186 self.name = name
1187 self.module = module
1188 self.cls = cls
1189 self.parent = cls or module
1190
1191 self.classes = collections.OrderedDict()
1192 self.functions = []
1193
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001194 def __repr__(self):
1195 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1196
Larry Hastings8666e652014-01-12 14:12:59 -08001197unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001198
Larry Hastings8666e652014-01-12 14:12:59 -08001199__abs__
1200__add__
1201__and__
1202__bytes__
1203__call__
1204__complex__
1205__delitem__
1206__divmod__
1207__eq__
1208__float__
1209__floordiv__
1210__ge__
1211__getattr__
1212__getattribute__
1213__getitem__
1214__gt__
1215__hash__
1216__iadd__
1217__iand__
1218__idivmod__
1219__ifloordiv__
1220__ilshift__
1221__imod__
1222__imul__
1223__index__
1224__int__
1225__invert__
1226__ior__
1227__ipow__
1228__irshift__
1229__isub__
1230__iter__
1231__itruediv__
1232__ixor__
1233__le__
1234__len__
1235__lshift__
1236__lt__
1237__mod__
1238__mul__
1239__neg__
1240__new__
1241__next__
1242__or__
1243__pos__
1244__pow__
1245__radd__
1246__rand__
1247__rdivmod__
1248__repr__
1249__rfloordiv__
1250__rlshift__
1251__rmod__
1252__rmul__
1253__ror__
1254__round__
1255__rpow__
1256__rrshift__
1257__rshift__
1258__rsub__
1259__rtruediv__
1260__rxor__
1261__setattr__
1262__setitem__
1263__str__
1264__sub__
1265__truediv__
1266__xor__
1267
1268""".strip().split())
1269
1270
1271INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6)
Larry Hastings31826802013-10-19 00:09:25 -07001272
1273class Function:
1274 """
1275 Mutable duck type for inspect.Function.
1276
1277 docstring - a str containing
1278 * embedded line breaks
1279 * text outdented to the left margin
1280 * no trailing whitespace.
1281 It will always be true that
1282 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1283 """
1284
1285 def __init__(self, parameters=None, *, name,
1286 module, cls=None, c_basename=None,
1287 full_name=None,
1288 return_converter, return_annotation=_empty,
1289 docstring=None, kind=CALLABLE, coexist=False):
1290 self.parameters = parameters or collections.OrderedDict()
1291 self.return_annotation = return_annotation
1292 self.name = name
1293 self.full_name = full_name
1294 self.module = module
1295 self.cls = cls
1296 self.parent = cls or module
1297 self.c_basename = c_basename
1298 self.return_converter = return_converter
1299 self.docstring = docstring or ''
1300 self.kind = kind
1301 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001302 self.self_converter = None
1303
1304 @property
1305 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001306 if self.kind in (METHOD_INIT, METHOD_NEW):
1307 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001308 flags = []
1309 if self.kind == CLASS_METHOD:
1310 flags.append('METH_CLASS')
1311 elif self.kind == STATIC_METHOD:
1312 flags.append('METH_STATIC')
1313 else:
1314 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1315 if self.coexist:
1316 flags.append('METH_COEXIST')
1317 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001318
1319 def __repr__(self):
1320 return '<clinic.Function ' + self.name + '>'
1321
1322
1323class Parameter:
1324 """
1325 Mutable duck type of inspect.Parameter.
1326 """
1327
1328 def __init__(self, name, kind, *, default=_empty,
1329 function, converter, annotation=_empty,
1330 docstring=None, group=0):
1331 self.name = name
1332 self.kind = kind
1333 self.default = default
1334 self.function = function
1335 self.converter = converter
1336 self.annotation = annotation
1337 self.docstring = docstring or ''
1338 self.group = group
1339
1340 def __repr__(self):
1341 return '<clinic.Parameter ' + self.name + '>'
1342
1343 def is_keyword_only(self):
1344 return self.kind == inspect.Parameter.KEYWORD_ONLY
1345
1346py_special_values = {
1347 NULL: "None",
1348}
1349
1350def py_repr(o):
1351 special = py_special_values.get(o)
1352 if special:
1353 return special
1354 return repr(o)
1355
1356
1357c_special_values = {
1358 NULL: "NULL",
1359 None: "Py_None",
1360}
1361
1362def c_repr(o):
1363 special = c_special_values.get(o)
1364 if special:
1365 return special
1366 if isinstance(o, str):
1367 return '"' + quoted_for_c_string(o) + '"'
1368 return repr(o)
1369
1370def add_c_converter(f, name=None):
1371 if not name:
1372 name = f.__name__
1373 if not name.endswith('_converter'):
1374 return f
1375 name = name[:-len('_converter')]
1376 converters[name] = f
1377 return f
1378
1379def add_default_legacy_c_converter(cls):
1380 # automatically add converter for default format unit
1381 # (but without stomping on the existing one if it's already
1382 # set, in case you subclass)
1383 if ((cls.format_unit != 'O&') and
1384 (cls.format_unit not in legacy_converters)):
1385 legacy_converters[cls.format_unit] = cls
1386 return cls
1387
1388def add_legacy_c_converter(format_unit, **kwargs):
1389 """
1390 Adds a legacy converter.
1391 """
1392 def closure(f):
1393 if not kwargs:
1394 added_f = f
1395 else:
1396 added_f = functools.partial(f, **kwargs)
1397 legacy_converters[format_unit] = added_f
1398 return f
1399 return closure
1400
1401class CConverterAutoRegister(type):
1402 def __init__(cls, name, bases, classdict):
1403 add_c_converter(cls)
1404 add_default_legacy_c_converter(cls)
1405
1406class CConverter(metaclass=CConverterAutoRegister):
1407 """
1408 For the init function, self, name, function, and default
1409 must be keyword-or-positional parameters. All other
1410 parameters (including "required" and "doc_default")
1411 must be keyword-only.
1412 """
1413
Larry Hastings78cf85c2014-01-04 12:44:57 -08001414 # The C type to use for this variable.
1415 # 'type' should be a Python string specifying the type, e.g. "int".
1416 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001417 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001418
1419 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001420 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001421 default = unspecified
1422
Larry Hastings4a55fc52014-01-12 11:09:57 -08001423 # If not None, default must be isinstance() of this type.
1424 # (You can also specify a tuple of types.)
1425 default_type = None
1426
Larry Hastings31826802013-10-19 00:09:25 -07001427 # "default" as it should appear in the documentation, as a string.
1428 # Or None if there is no default.
1429 doc_default = None
1430
Larry Hastingsabc716b2013-11-20 09:13:52 -08001431 # "default" converted into a str for rendering into Python code.
1432 py_default = None
1433
Larry Hastings31826802013-10-19 00:09:25 -07001434 # "default" converted into a C value, as a string.
1435 # Or None if there is no default.
1436 c_default = None
1437
Larry Hastingsabc716b2013-11-20 09:13:52 -08001438 # The default value used to initialize the C variable when
1439 # there is no default, but not specifying a default may
1440 # result in an "uninitialized variable" warning. This can
1441 # easily happen when using option groups--although
1442 # properly-written code won't actually use the variable,
1443 # the variable does get passed in to the _impl. (Ah, if
1444 # only dataflow analysis could inline the static function!)
1445 #
1446 # This value is specified as a string.
1447 # Every non-abstract subclass should supply a valid value.
1448 c_ignored_default = 'NULL'
1449
Larry Hastings31826802013-10-19 00:09:25 -07001450 # The C converter *function* to be used, if any.
1451 # (If this is not None, format_unit must be 'O&'.)
1452 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001453
Larry Hastings78cf85c2014-01-04 12:44:57 -08001454 # Should Argument Clinic add a '&' before the name of
1455 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001456 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001457
1458 # Should Argument Clinic add a '&' before the name of
1459 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001460 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001461
1462 #############################################################
1463 #############################################################
1464 ## You shouldn't need to read anything below this point to ##
1465 ## write your own converter functions. ##
1466 #############################################################
1467 #############################################################
1468
1469 # The "format unit" to specify for this variable when
1470 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1471 # Custom converters should always use the default value of 'O&'.
1472 format_unit = 'O&'
1473
1474 # What encoding do we want for this variable? Only used
1475 # by format units starting with 'e'.
1476 encoding = None
1477
Larry Hastings77561cc2014-01-07 12:13:13 -08001478 # Should this object be required to be a subclass of a specific type?
1479 # If not None, should be a string representing a pointer to a
1480 # PyTypeObject (e.g. "&PyUnicode_Type").
1481 # Only used by the 'O!' format unit (and the "object" converter).
1482 subclass_of = None
1483
Larry Hastings78cf85c2014-01-04 12:44:57 -08001484 # Do we want an adjacent '_length' variable for this variable?
1485 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001486 length = False
1487
Larry Hastings16c51912014-01-07 11:53:01 -08001488 def __init__(self, name, function, default=unspecified, *, doc_default=None, c_default=None, py_default=None, required=False, annotation=unspecified, **kwargs):
Larry Hastings31826802013-10-19 00:09:25 -07001489 self.function = function
1490 self.name = name
1491
1492 if default is not unspecified:
Larry Hastings4a55fc52014-01-12 11:09:57 -08001493 if self.default_type and not isinstance(default, self.default_type):
1494 if isinstance(self.default_type, type):
1495 types_str = self.default_type.__name__
1496 else:
1497 types_str = ', '.join((cls.__name__ for cls in self.default_type))
1498 fail("{}: default value {!r} for field {} is not of type {}".format(
1499 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07001500 self.default = default
Larry Hastings16c51912014-01-07 11:53:01 -08001501 self.py_default = py_default if py_default is not None else py_repr(default)
Larry Hastings31826802013-10-19 00:09:25 -07001502 self.doc_default = doc_default if doc_default is not None else self.py_default
Larry Hastings16c51912014-01-07 11:53:01 -08001503 self.c_default = c_default if c_default is not None else c_repr(default)
Larry Hastings4a55fc52014-01-12 11:09:57 -08001504 else:
1505 self.py_default = py_default
1506 self.doc_default = doc_default
1507 self.c_default = c_default
Larry Hastings31826802013-10-19 00:09:25 -07001508 if annotation != unspecified:
1509 fail("The 'annotation' parameter is not currently permitted.")
1510 self.required = required
1511 self.converter_init(**kwargs)
1512
1513 def converter_init(self):
1514 pass
1515
1516 def is_optional(self):
1517 return (self.default is not unspecified) and (not self.required)
1518
1519 def render(self, parameter, data):
1520 """
1521 parameter is a clinic.Parameter instance.
1522 data is a CRenderData instance.
1523 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001524 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08001525 original_name = self.name
1526 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001527
1528 # declarations
1529 d = self.declaration()
1530 data.declarations.append(d)
1531
1532 # initializers
1533 initializers = self.initialize()
1534 if initializers:
1535 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1536
1537 # impl_arguments
1538 s = ("&" if self.impl_by_reference else "") + name
1539 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001540 if self.length:
1541 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001542
1543 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08001544 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001545
1546 # format_units
1547 if self.is_optional() and '|' not in data.format_units:
1548 data.format_units.append('|')
1549 if parameter.is_keyword_only() and '$' not in data.format_units:
1550 data.format_units.append('$')
1551 data.format_units.append(self.format_unit)
1552
1553 # parse_arguments
1554 self.parse_argument(data.parse_arguments)
1555
1556 # impl_parameters
1557 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001558 if self.length:
1559 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001560
1561 # cleanup
1562 cleanup = self.cleanup()
1563 if cleanup:
1564 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1565
Larry Hastingsebdcb502013-11-23 14:54:00 -08001566 def length_name(self):
1567 """Computes the name of the associated "length" variable."""
1568 if not self.length:
1569 return None
1570 return ensure_legal_c_identifier(self.name) + "_length"
1571
Larry Hastings31826802013-10-19 00:09:25 -07001572 # Why is this one broken out separately?
1573 # For "positional-only" function parsing,
1574 # which generates a bunch of PyArg_ParseTuple calls.
1575 def parse_argument(self, list):
1576 assert not (self.converter and self.encoding)
1577 if self.format_unit == 'O&':
1578 assert self.converter
1579 list.append(self.converter)
1580
1581 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08001582 list.append(c_repr(self.encoding))
1583 elif self.subclass_of:
1584 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07001585
Larry Hastingsebdcb502013-11-23 14:54:00 -08001586 legal_name = ensure_legal_c_identifier(self.name)
1587 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001588 list.append(s)
1589
Larry Hastingsebdcb502013-11-23 14:54:00 -08001590 if self.length:
1591 list.append("&" + self.length_name())
1592
Larry Hastings31826802013-10-19 00:09:25 -07001593 #
1594 # All the functions after here are intended as extension points.
1595 #
1596
1597 def simple_declaration(self, by_reference=False):
1598 """
1599 Computes the basic declaration of the variable.
1600 Used in computing the prototype declaration and the
1601 variable declaration.
1602 """
1603 prototype = [self.type]
1604 if by_reference or not self.type.endswith('*'):
1605 prototype.append(" ")
1606 if by_reference:
1607 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001608 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001609 return "".join(prototype)
1610
1611 def declaration(self):
1612 """
1613 The C statement to declare this variable.
1614 """
1615 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08001616 default = self.c_default
1617 if not default and self.parameter.group:
1618 default = self.c_ignored_default
1619 if default:
Larry Hastings31826802013-10-19 00:09:25 -07001620 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08001621 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07001622 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001623 if self.length:
1624 declaration.append('\nPy_ssize_clean_t ')
1625 declaration.append(self.length_name())
1626 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08001627 s = "".join(declaration)
1628 # double up curly-braces, this string will be used
1629 # as part of a format_map() template later
1630 s = s.replace("{", "{{")
1631 s = s.replace("}", "}}")
1632 return s
Larry Hastings31826802013-10-19 00:09:25 -07001633
1634 def initialize(self):
1635 """
1636 The C statements required to set up this variable before parsing.
1637 Returns a string containing this code indented at column 0.
1638 If no initialization is necessary, returns an empty string.
1639 """
1640 return ""
1641
1642 def cleanup(self):
1643 """
1644 The C statements required to clean up after this variable.
1645 Returns a string containing this code indented at column 0.
1646 If no cleanup is necessary, returns an empty string.
1647 """
1648 return ""
1649
1650
1651class bool_converter(CConverter):
1652 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001653 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07001654 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001655 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07001656
1657 def converter_init(self):
1658 self.default = bool(self.default)
1659 self.c_default = str(int(self.default))
1660
1661class char_converter(CConverter):
1662 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001663 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07001664 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001665 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001666
Larry Hastings4a55fc52014-01-12 11:09:57 -08001667 def converter_init(self):
1668 if len(self.default) != 1:
1669 fail("char_converter: illegal default value " + repr(self.default))
1670
1671
Larry Hastings31826802013-10-19 00:09:25 -07001672@add_legacy_c_converter('B', bitwise=True)
1673class byte_converter(CConverter):
1674 type = 'byte'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001675 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001676 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001677 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001678
1679 def converter_init(self, *, bitwise=False):
1680 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001681 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07001682
1683class short_converter(CConverter):
1684 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001685 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001686 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001687 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001688
1689class unsigned_short_converter(CConverter):
1690 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001691 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001692 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001693 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001694
1695 def converter_init(self, *, bitwise=False):
1696 if not bitwise:
1697 fail("Unsigned shorts must be bitwise (for now).")
1698
Larry Hastingsebdcb502013-11-23 14:54:00 -08001699@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07001700class int_converter(CConverter):
1701 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001702 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001703 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001704 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001705
Larry Hastingsebdcb502013-11-23 14:54:00 -08001706 def converter_init(self, *, types='int'):
1707 if types == 'str':
1708 self.format_unit = 'C'
1709 elif types != 'int':
1710 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07001711
1712class unsigned_int_converter(CConverter):
1713 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001714 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001715 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001716 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001717
1718 def converter_init(self, *, bitwise=False):
1719 if not bitwise:
1720 fail("Unsigned ints must be bitwise (for now).")
1721
1722class long_converter(CConverter):
1723 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001724 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001725 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001726 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001727
1728class unsigned_long_converter(CConverter):
1729 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001730 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001731 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001732 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001733
1734 def converter_init(self, *, bitwise=False):
1735 if not bitwise:
1736 fail("Unsigned longs must be bitwise (for now).")
1737
1738class PY_LONG_LONG_converter(CConverter):
1739 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001740 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001741 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001742 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001743
1744class unsigned_PY_LONG_LONG_converter(CConverter):
1745 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001746 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001747 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001748 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001749
1750 def converter_init(self, *, bitwise=False):
1751 if not bitwise:
1752 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
1753
1754class Py_ssize_t_converter(CConverter):
1755 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001756 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001757 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001758 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001759
1760
1761class float_converter(CConverter):
1762 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001763 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07001764 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001765 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001766
1767class double_converter(CConverter):
1768 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001769 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07001770 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001771 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001772
1773
1774class Py_complex_converter(CConverter):
1775 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001776 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07001777 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001778 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07001779
1780
1781class object_converter(CConverter):
1782 type = 'PyObject *'
1783 format_unit = 'O'
1784
Larry Hastings4a55fc52014-01-12 11:09:57 -08001785 def converter_init(self, *, converter=None, type=None, subclass_of=None):
1786 if converter:
1787 if subclass_of:
1788 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
1789 self.format_unit = 'O&'
1790 self.converter = converter
1791 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07001792 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08001793 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08001794
Larry Hastings77561cc2014-01-07 12:13:13 -08001795 if type is not None:
1796 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07001797
1798
Larry Hastingsebdcb502013-11-23 14:54:00 -08001799@add_legacy_c_converter('s#', length=True)
1800@add_legacy_c_converter('y', type="bytes")
1801@add_legacy_c_converter('y#', type="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001802@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001803@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001804class str_converter(CConverter):
1805 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001806 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001807 format_unit = 's'
1808
Larry Hastingsebdcb502013-11-23 14:54:00 -08001809 def converter_init(self, *, encoding=None, types="str",
1810 length=False, nullable=False, zeroes=False):
1811
1812 types = set(types.strip().split())
1813 bytes_type = set(("bytes",))
1814 str_type = set(("str",))
1815 all_3_type = set(("bytearray",)) | bytes_type | str_type
1816 is_bytes = types == bytes_type
1817 is_str = types == str_type
1818 is_all_3 = types == all_3_type
1819
1820 self.length = bool(length)
1821 format_unit = None
1822
1823 if encoding:
1824 self.encoding = encoding
1825
1826 if is_str and not (length or zeroes or nullable):
1827 format_unit = 'es'
1828 elif is_all_3 and not (length or zeroes or nullable):
1829 format_unit = 'et'
1830 elif is_str and length and zeroes and not nullable:
1831 format_unit = 'es#'
1832 elif is_all_3 and length and not (nullable or zeroes):
1833 format_unit = 'et#'
1834
1835 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08001836 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001837 # TODO set pointer to NULL
1838 # TODO add cleanup for buffer
1839 pass
1840
1841 else:
1842 if zeroes:
1843 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
1844
1845 if is_bytes and not (nullable or length):
1846 format_unit = 'y'
1847 elif is_bytes and length and not nullable:
1848 format_unit = 'y#'
1849 elif is_str and not (nullable or length):
1850 format_unit = 's'
1851 elif is_str and length and not nullable:
1852 format_unit = 's#'
1853 elif is_str and nullable and not length:
1854 format_unit = 'z'
1855 elif is_str and nullable and length:
1856 format_unit = 'z#'
1857
1858 if not format_unit:
1859 fail("str_converter: illegal combination of arguments")
1860 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001861
1862
1863class PyBytesObject_converter(CConverter):
1864 type = 'PyBytesObject *'
1865 format_unit = 'S'
1866
1867class PyByteArrayObject_converter(CConverter):
1868 type = 'PyByteArrayObject *'
1869 format_unit = 'Y'
1870
1871class unicode_converter(CConverter):
1872 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001873 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001874 format_unit = 'U'
1875
Larry Hastingsebdcb502013-11-23 14:54:00 -08001876@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001877@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001878@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001879class Py_UNICODE_converter(CConverter):
1880 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001881 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001882 format_unit = 'u'
1883
Larry Hastingsebdcb502013-11-23 14:54:00 -08001884 def converter_init(self, *, nullable=False, length=False):
1885 format_unit = 'Z' if nullable else 'u'
1886 if length:
1887 format_unit += '#'
1888 self.length = True
1889 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001890
Larry Hastingsebdcb502013-11-23 14:54:00 -08001891#
1892# We define three string conventions for buffer types in the 'types' argument:
1893# 'buffer' : any object supporting the buffer interface
1894# 'rwbuffer': any object supporting the buffer interface, but must be writeable
1895# 'robuffer': any object supporting the buffer interface, but must not be writeable
1896#
1897@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
1898@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
1899@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07001900class Py_buffer_converter(CConverter):
1901 type = 'Py_buffer'
1902 format_unit = 'y*'
1903 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08001904 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07001905
Larry Hastingsebdcb502013-11-23 14:54:00 -08001906 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08001907 if self.default not in (unspecified, None):
1908 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08001909 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08001910 types = set(types.strip().split())
1911 bytes_type = set(('bytes',))
1912 bytearray_type = set(('bytearray',))
1913 buffer_type = set(('buffer',))
1914 rwbuffer_type = set(('rwbuffer',))
1915 robuffer_type = set(('robuffer',))
1916 str_type = set(('str',))
1917 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
1918
1919 format_unit = None
1920 if types == (str_type | bytes_bytearray_buffer_type):
1921 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07001922 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001923 if nullable:
1924 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
1925 elif types == (bytes_bytearray_buffer_type):
1926 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001927 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001928 format_unit = 'w*'
1929 if not format_unit:
1930 fail("Py_buffer_converter: illegal combination of arguments")
1931
1932 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001933
1934 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001935 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08001936 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08001937
1938
1939class self_converter(CConverter):
1940 """
1941 A special-case converter:
1942 this is the default converter used for "self".
1943 """
1944 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08001945 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001946 f = self.function
Larry Hastings8666e652014-01-12 14:12:59 -08001947 if f.kind in (CALLABLE, METHOD_INIT):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001948 if f.cls:
1949 self.name = "self"
1950 else:
1951 self.name = "module"
1952 self.type = "PyModuleDef *"
1953 elif f.kind == STATIC_METHOD:
1954 self.name = "null"
1955 self.type = "void *"
1956 elif f.kind == CLASS_METHOD:
1957 self.name = "cls"
1958 self.type = "PyTypeObject *"
Larry Hastings8666e652014-01-12 14:12:59 -08001959 elif f.kind == METHOD_NEW:
1960 self.name = "type"
1961 self.type = "PyTypeObject *"
Larry Hastingsebdcb502013-11-23 14:54:00 -08001962
Larry Hastings78cf85c2014-01-04 12:44:57 -08001963 if type:
1964 self.type = type
1965
Larry Hastingsebdcb502013-11-23 14:54:00 -08001966 def render(self, parameter, data):
1967 fail("render() should never be called on self_converter instances")
1968
Larry Hastings31826802013-10-19 00:09:25 -07001969
1970
1971def add_c_return_converter(f, name=None):
1972 if not name:
1973 name = f.__name__
1974 if not name.endswith('_return_converter'):
1975 return f
1976 name = name[:-len('_return_converter')]
1977 return_converters[name] = f
1978 return f
1979
1980
1981class CReturnConverterAutoRegister(type):
1982 def __init__(cls, name, bases, classdict):
1983 add_c_return_converter(cls)
1984
1985class CReturnConverter(metaclass=CReturnConverterAutoRegister):
1986
Larry Hastings78cf85c2014-01-04 12:44:57 -08001987 # The C type to use for this variable.
1988 # 'type' should be a Python string specifying the type, e.g. "int".
1989 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001990 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08001991
1992 # The Python default value for this parameter, as a Python value.
1993 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001994 default = None
1995
1996 def __init__(self, *, doc_default=None, **kwargs):
1997 self.doc_default = doc_default
1998 try:
1999 self.return_converter_init(**kwargs)
2000 except TypeError as e:
2001 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
2002 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
2003
2004 def return_converter_init(self):
2005 pass
2006
2007 def declare(self, data, name="_return_value"):
2008 line = []
2009 add = line.append
2010 add(self.type)
2011 if not self.type.endswith('*'):
2012 add(' ')
2013 add(name + ';')
2014 data.declarations.append(''.join(line))
2015 data.return_value = name
2016
2017 def err_occurred_if(self, expr, data):
2018 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2019
2020 def err_occurred_if_null_pointer(self, variable, data):
2021 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2022
2023 def render(self, function, data):
2024 """
2025 function is a clinic.Function instance.
2026 data is a CRenderData instance.
2027 """
2028 pass
2029
2030add_c_return_converter(CReturnConverter, 'object')
2031
Larry Hastings78cf85c2014-01-04 12:44:57 -08002032class NoneType_return_converter(CReturnConverter):
2033 def render(self, function, data):
2034 self.declare(data)
2035 data.return_conversion.append('''
2036if (_return_value != Py_None)
2037 goto exit;
2038return_value = Py_None;
2039Py_INCREF(Py_None);
2040'''.strip())
2041
Larry Hastings4a55fc52014-01-12 11:09:57 -08002042class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002043 type = 'int'
2044
2045 def render(self, function, data):
2046 self.declare(data)
2047 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002048 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002049
2050class long_return_converter(CReturnConverter):
2051 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002052 conversion_fn = 'PyLong_FromLong'
2053 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002054
2055 def render(self, function, data):
2056 self.declare(data)
2057 self.err_occurred_if("_return_value == -1", data)
2058 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002059 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002060
Larry Hastings4a55fc52014-01-12 11:09:57 -08002061class int_return_converter(long_return_converter):
2062 type = 'int'
2063 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002064
Larry Hastings4a55fc52014-01-12 11:09:57 -08002065class unsigned_long_return_converter(long_return_converter):
2066 type = 'unsigned long'
2067 conversion_fn = 'PyLong_FromUnsignedLong'
2068
2069class unsigned_int_return_converter(unsigned_long_return_converter):
2070 type = 'unsigned int'
2071 cast = '(unsigned long)'
2072
2073class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002074 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002075 conversion_fn = 'PyLong_FromSsize_t'
2076
2077class size_t_return_converter(long_return_converter):
2078 type = 'size_t'
2079 conversion_fn = 'PyLong_FromSize_t'
2080
2081
2082class double_return_converter(CReturnConverter):
2083 type = 'double'
2084 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002085
2086 def render(self, function, data):
2087 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002088 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002089 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002090 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2091
2092class float_return_converter(double_return_converter):
2093 type = 'float'
2094 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002095
2096
2097class DecodeFSDefault_return_converter(CReturnConverter):
2098 type = 'char *'
2099
2100 def render(self, function, data):
2101 self.declare(data)
2102 self.err_occurred_if_null_pointer("_return_value", data)
2103 data.return_conversion.append(
2104 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2105
2106
2107class IndentStack:
2108 def __init__(self):
2109 self.indents = []
2110 self.margin = None
2111
2112 def _ensure(self):
2113 if not self.indents:
2114 fail('IndentStack expected indents, but none are defined.')
2115
2116 def measure(self, line):
2117 """
2118 Returns the length of the line's margin.
2119 """
2120 if '\t' in line:
2121 fail('Tab characters are illegal in the Clinic DSL.')
2122 stripped = line.lstrip()
2123 if not len(stripped):
2124 # we can't tell anything from an empty line
2125 # so just pretend it's indented like our current indent
2126 self._ensure()
2127 return self.indents[-1]
2128 return len(line) - len(stripped)
2129
2130 def infer(self, line):
2131 """
2132 Infer what is now the current margin based on this line.
2133 Returns:
2134 1 if we have indented (or this is the first margin)
2135 0 if the margin has not changed
2136 -N if we have dedented N times
2137 """
2138 indent = self.measure(line)
2139 margin = ' ' * indent
2140 if not self.indents:
2141 self.indents.append(indent)
2142 self.margin = margin
2143 return 1
2144 current = self.indents[-1]
2145 if indent == current:
2146 return 0
2147 if indent > current:
2148 self.indents.append(indent)
2149 self.margin = margin
2150 return 1
2151 # indent < current
2152 if indent not in self.indents:
2153 fail("Illegal outdent.")
2154 outdent_count = 0
2155 while indent != current:
2156 self.indents.pop()
2157 current = self.indents[-1]
2158 outdent_count -= 1
2159 self.margin = margin
2160 return outdent_count
2161
2162 @property
2163 def depth(self):
2164 """
2165 Returns how many margins are currently defined.
2166 """
2167 return len(self.indents)
2168
2169 def indent(self, line):
2170 """
2171 Indents a line by the currently defined margin.
2172 """
2173 return self.margin + line
2174
2175 def dedent(self, line):
2176 """
2177 Dedents a line by the currently defined margin.
2178 (The inverse of 'indent'.)
2179 """
2180 margin = self.margin
2181 indent = self.indents[-1]
2182 if not line.startswith(margin):
2183 fail('Cannot dedent, line does not start with the previous margin:')
2184 return line[indent:]
2185
2186
2187class DSLParser:
2188 def __init__(self, clinic):
2189 self.clinic = clinic
2190
2191 self.directives = {}
2192 for name in dir(self):
2193 # functions that start with directive_ are added to directives
2194 _, s, key = name.partition("directive_")
2195 if s:
2196 self.directives[key] = getattr(self, name)
2197
2198 # functions that start with at_ are too, with an @ in front
2199 _, s, key = name.partition("at_")
2200 if s:
2201 self.directives['@' + key] = getattr(self, name)
2202
2203 self.reset()
2204
2205 def reset(self):
2206 self.function = None
2207 self.state = self.state_dsl_start
2208 self.parameter_indent = None
2209 self.keyword_only = False
2210 self.group = 0
2211 self.parameter_state = self.ps_start
2212 self.indent = IndentStack()
2213 self.kind = CALLABLE
2214 self.coexist = False
2215
Larry Hastingsebdcb502013-11-23 14:54:00 -08002216 def directive_version(self, required):
2217 global version
2218 if version_comparitor(version, required) < 0:
2219 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2220
Larry Hastings31826802013-10-19 00:09:25 -07002221 def directive_module(self, name):
2222 fields = name.split('.')
2223 new = fields.pop()
2224 module, cls = self.clinic._module_and_class(fields)
2225 if cls:
2226 fail("Can't nest a module inside a class!")
2227 m = Module(name, module)
2228 module.modules[name] = m
2229 self.block.signatures.append(m)
2230
2231 def directive_class(self, name):
2232 fields = name.split('.')
2233 in_classes = False
2234 parent = self
2235 name = fields.pop()
2236 so_far = []
2237 module, cls = self.clinic._module_and_class(fields)
2238
Larry Hastings31826802013-10-19 00:09:25 -07002239 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002240 if cls:
2241 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002242 else:
2243 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002244 self.block.signatures.append(c)
2245
2246 def at_classmethod(self):
2247 assert self.kind is CALLABLE
2248 self.kind = CLASS_METHOD
2249
2250 def at_staticmethod(self):
2251 assert self.kind is CALLABLE
2252 self.kind = STATIC_METHOD
2253
2254 def at_coexist(self):
2255 assert self.coexist == False
2256 self.coexist = True
2257
Larry Hastingsebdcb502013-11-23 14:54:00 -08002258
Larry Hastings31826802013-10-19 00:09:25 -07002259 def parse(self, block):
2260 self.reset()
2261 self.block = block
2262 block_start = self.clinic.block_parser.line_number
2263 lines = block.input.split('\n')
2264 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2265 if '\t' in line:
2266 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2267 self.state(line)
2268
2269 self.next(self.state_terminal)
2270 self.state(None)
2271
2272 block.output = self.clinic.language.render(block.signatures)
2273
2274 @staticmethod
2275 def ignore_line(line):
2276 # ignore comment-only lines
2277 if line.lstrip().startswith('#'):
2278 return True
2279
2280 # Ignore empty lines too
2281 # (but not in docstring sections!)
2282 if not line.strip():
2283 return True
2284
2285 return False
2286
2287 @staticmethod
2288 def calculate_indent(line):
2289 return len(line) - len(line.strip())
2290
2291 def next(self, state, line=None):
2292 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2293 self.state = state
2294 if line is not None:
2295 self.state(line)
2296
2297 def state_dsl_start(self, line):
2298 # self.block = self.ClinicOutputBlock(self)
2299 if self.ignore_line(line):
2300 return
2301 self.next(self.state_modulename_name, line)
2302
2303 def state_modulename_name(self, line):
2304 # looking for declaration, which establishes the leftmost column
2305 # line should be
2306 # modulename.fnname [as c_basename] [-> return annotation]
2307 # square brackets denote optional syntax.
2308 #
Larry Hastings4a714d42014-01-14 22:22:41 -08002309 # alternatively:
2310 # modulename.fnname [as c_basename] = modulename.existing_fn_name
2311 # clones the parameters and return converter from that
2312 # function. you can't modify them. you must enter a
2313 # new docstring.
2314 #
Larry Hastings31826802013-10-19 00:09:25 -07002315 # (but we might find a directive first!)
2316 #
2317 # this line is permitted to start with whitespace.
2318 # we'll call this number of spaces F (for "function").
2319
2320 if not line.strip():
2321 return
2322
2323 self.indent.infer(line)
2324
2325 # is it a directive?
2326 fields = shlex.split(line)
2327 directive_name = fields[0]
2328 directive = self.directives.get(directive_name, None)
2329 if directive:
2330 directive(*fields[1:])
2331 return
2332
Larry Hastings4a714d42014-01-14 22:22:41 -08002333 # are we cloning?
2334 before, equals, existing = line.rpartition('=')
2335 if equals:
2336 full_name, _, c_basename = before.partition(' as ')
2337 full_name = full_name.strip()
2338 c_basename = c_basename.strip()
2339 existing = existing.strip()
2340 if (is_legal_py_identifier(full_name) and
2341 (not c_basename or is_legal_c_identifier(c_basename)) and
2342 is_legal_py_identifier(existing)):
2343 # we're cloning!
2344 fields = [x.strip() for x in existing.split('.')]
2345 function_name = fields.pop()
2346 module, cls = self.clinic._module_and_class(fields)
2347
2348 for existing_function in (cls or module).functions:
2349 if existing_function.name == function_name:
2350 break
2351 else:
2352 existing_function = None
2353 if not existing_function:
2354 fail("Couldn't find existing function " + repr(existing) + "!")
2355
2356 fields = [x.strip() for x in full_name.split('.')]
2357 function_name = fields.pop()
2358 module, cls = self.clinic._module_and_class(fields)
2359
2360 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
2361 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
2362 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2363 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
2364
2365 self.function.parameters = existing_function.parameters.copy()
2366
2367 self.block.signatures.append(self.function)
2368 (cls or module).functions.append(self.function)
2369 self.next(self.state_function_docstring)
2370 return
2371
Larry Hastings31826802013-10-19 00:09:25 -07002372 line, _, returns = line.partition('->')
2373
2374 full_name, _, c_basename = line.partition(' as ')
2375 full_name = full_name.strip()
2376 c_basename = c_basename.strip() or None
2377
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002378 if not is_legal_py_identifier(full_name):
2379 fail("Illegal function name: {}".format(full_name))
2380 if c_basename and not is_legal_c_identifier(c_basename):
2381 fail("Illegal C basename: {}".format(c_basename))
2382
Larry Hastings31826802013-10-19 00:09:25 -07002383 if not returns:
2384 return_converter = CReturnConverter()
2385 else:
2386 ast_input = "def x() -> {}: pass".format(returns)
2387 module = None
2388 try:
2389 module = ast.parse(ast_input)
2390 except SyntaxError:
2391 pass
2392 if not module:
2393 fail("Badly-formed annotation for " + full_name + ": " + returns)
2394 try:
2395 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002396 if legacy:
2397 fail("Legacy converter {!r} not allowed as a return converter"
2398 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07002399 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002400 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07002401 return_converter = return_converters[name](**kwargs)
2402 except ValueError:
2403 fail("Badly-formed annotation for " + full_name + ": " + returns)
2404
2405 fields = [x.strip() for x in full_name.split('.')]
2406 function_name = fields.pop()
2407 module, cls = self.clinic._module_and_class(fields)
2408
Larry Hastings8666e652014-01-12 14:12:59 -08002409 fields = full_name.split('.')
2410 if fields[-1] == '__new__':
2411 if (self.kind != CLASS_METHOD) or (not cls):
2412 fail("__new__ must be a class method!")
2413 self.kind = METHOD_NEW
2414 elif fields[-1] == '__init__':
2415 if (self.kind != CALLABLE) or (not cls):
2416 fail("__init__ must be a normal method, not a class or static method!")
2417 self.kind = METHOD_INIT
2418 elif fields[-1] in unsupported_special_methods:
2419 fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
2420
Larry Hastings31826802013-10-19 00:09:25 -07002421 if not module:
2422 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2423 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2424 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2425 self.block.signatures.append(self.function)
Larry Hastings4a714d42014-01-14 22:22:41 -08002426 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07002427 self.next(self.state_parameters_start)
2428
2429 # Now entering the parameters section. The rules, formally stated:
2430 #
2431 # * All lines must be indented with spaces only.
2432 # * The first line must be a parameter declaration.
2433 # * The first line must be indented.
2434 # * This first line establishes the indent for parameters.
2435 # * We'll call this number of spaces P (for "parameter").
2436 # * Thenceforth:
2437 # * Lines indented with P spaces specify a parameter.
2438 # * Lines indented with > P spaces are docstrings for the previous
2439 # parameter.
2440 # * We'll call this number of spaces D (for "docstring").
2441 # * All subsequent lines indented with >= D spaces are stored as
2442 # part of the per-parameter docstring.
2443 # * All lines will have the first D spaces of the indent stripped
2444 # before they are stored.
2445 # * It's illegal to have a line starting with a number of spaces X
2446 # such that P < X < D.
2447 # * A line with < P spaces is the first line of the function
2448 # docstring, which ends processing for parameters and per-parameter
2449 # docstrings.
2450 # * The first line of the function docstring must be at the same
2451 # indent as the function declaration.
2452 # * It's illegal to have any line in the parameters section starting
2453 # with X spaces such that F < X < P. (As before, F is the indent
2454 # of the function declaration.)
2455 #
2456 ##############
2457 #
2458 # Also, currently Argument Clinic places the following restrictions on groups:
2459 # * Each group must contain at least one parameter.
2460 # * Each group may contain at most one group, which must be the furthest
2461 # thing in the group from the required parameters. (The nested group
2462 # must be the first in the group when it's before the required
2463 # parameters, and the last thing in the group when after the required
2464 # parameters.)
2465 # * There may be at most one (top-level) group to the left or right of
2466 # the required parameters.
2467 # * You must specify a slash, and it must be after all parameters.
2468 # (In other words: either all parameters are positional-only,
2469 # or none are.)
2470 #
2471 # Said another way:
2472 # * Each group must contain at least one parameter.
2473 # * All left square brackets before the required parameters must be
2474 # consecutive. (You can't have a left square bracket followed
2475 # by a parameter, then another left square bracket. You can't
2476 # have a left square bracket, a parameter, a right square bracket,
2477 # and then a left square bracket.)
2478 # * All right square brackets after the required parameters must be
2479 # consecutive.
2480 #
2481 # These rules are enforced with a single state variable:
2482 # "parameter_state". (Previously the code was a miasma of ifs and
2483 # separate boolean state variables.) The states are:
2484 #
2485 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2486 # 01 2 3 4 5 6 <- state transitions
2487 #
2488 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2489 # 1: ps_left_square_before. left square brackets before required parameters.
2490 # 2: ps_group_before. in a group, before required parameters.
2491 # 3: ps_required. required parameters. (renumber left groups!)
2492 # 4: ps_group_after. in a group, after required parameters.
2493 # 5: ps_right_square_after. right square brackets after required parameters.
2494 # 6: ps_seen_slash. seen slash.
2495 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2496 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2497
2498 def state_parameters_start(self, line):
2499 if self.ignore_line(line):
2500 return
2501
2502 # if this line is not indented, we have no parameters
2503 if not self.indent.infer(line):
2504 return self.next(self.state_function_docstring, line)
2505
2506 return self.next(self.state_parameter, line)
2507
2508
2509 def to_required(self):
2510 """
2511 Transition to the "required" parameter state.
2512 """
2513 if self.parameter_state != self.ps_required:
2514 self.parameter_state = self.ps_required
2515 for p in self.function.parameters.values():
2516 p.group = -p.group
2517
2518 def state_parameter(self, line):
2519 if self.ignore_line(line):
2520 return
2521
2522 assert self.indent.depth == 2
2523 indent = self.indent.infer(line)
2524 if indent == -1:
2525 # we outdented, must be to definition column
2526 return self.next(self.state_function_docstring, line)
2527
2528 if indent == 1:
2529 # we indented, must be to new parameter docstring column
2530 return self.next(self.state_parameter_docstring_start, line)
2531
2532 line = line.lstrip()
2533
2534 if line in ('*', '/', '[', ']'):
2535 self.parse_special_symbol(line)
2536 return
2537
2538 if self.parameter_state in (self.ps_start, self.ps_required):
2539 self.to_required()
2540 elif self.parameter_state == self.ps_left_square_before:
2541 self.parameter_state = self.ps_group_before
2542 elif self.parameter_state == self.ps_group_before:
2543 if not self.group:
2544 self.to_required()
2545 elif self.parameter_state == self.ps_group_after:
2546 pass
2547 else:
2548 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2549
2550 ast_input = "def x({}): pass".format(line)
2551 module = None
2552 try:
2553 module = ast.parse(ast_input)
2554 except SyntaxError:
2555 pass
2556 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07002557 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07002558
2559 function_args = module.body[0].args
2560 parameter = function_args.args[0]
2561
Larry Hastings16c51912014-01-07 11:53:01 -08002562 py_default = None
2563
2564 parameter_name = parameter.arg
2565 name, legacy, kwargs = self.parse_converter(parameter.annotation)
2566
Larry Hastings31826802013-10-19 00:09:25 -07002567 if function_args.defaults:
2568 expr = function_args.defaults[0]
2569 # mild hack: explicitly support NULL as a default value
2570 if isinstance(expr, ast.Name) and expr.id == 'NULL':
2571 value = NULL
Larry Hastings16c51912014-01-07 11:53:01 -08002572 elif isinstance(expr, ast.Attribute):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002573 c_default = kwargs.get("c_default")
2574 if not (isinstance(c_default, str) and c_default):
2575 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
2576
Larry Hastings16c51912014-01-07 11:53:01 -08002577 a = []
2578 n = expr
2579 while isinstance(n, ast.Attribute):
2580 a.append(n.attr)
2581 n = n.value
2582 if not isinstance(n, ast.Name):
2583 fail("Malformed default value (looked like a Python constant)")
2584 a.append(n.id)
2585 py_default = ".".join(reversed(a))
Larry Hastings16c51912014-01-07 11:53:01 -08002586 kwargs["py_default"] = py_default
Larry Hastings4a55fc52014-01-12 11:09:57 -08002587 value = eval(py_default)
Larry Hastings31826802013-10-19 00:09:25 -07002588 else:
2589 value = ast.literal_eval(expr)
2590 else:
2591 value = unspecified
2592
Larry Hastings31826802013-10-19 00:09:25 -07002593 dict = legacy_converters if legacy else converters
2594 legacy_str = "legacy " if legacy else ""
2595 if name not in dict:
2596 fail('{} is not a valid {}converter'.format(name, legacy_str))
2597 converter = dict[name](parameter_name, self.function, value, **kwargs)
2598
Larry Hastingsebdcb502013-11-23 14:54:00 -08002599 # special case: if it's the self converter,
2600 # don't actually add it to the parameter list
2601 if isinstance(converter, self_converter):
2602 if self.function.parameters or (self.parameter_state != self.ps_required):
2603 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
2604 if self.function.self_converter:
2605 fail("You can't specify the 'self' parameter more than once.")
2606 self.function.self_converter = converter
2607 self.parameter_state = self.ps_start
2608 return
2609
Larry Hastings31826802013-10-19 00:09:25 -07002610 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
2611 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
2612 self.function.parameters[parameter_name] = p
2613
2614 def parse_converter(self, annotation):
2615 if isinstance(annotation, ast.Str):
2616 return annotation.s, True, {}
2617
2618 if isinstance(annotation, ast.Name):
2619 return annotation.id, False, {}
2620
Larry Hastings4a55fc52014-01-12 11:09:57 -08002621 if not isinstance(annotation, ast.Call):
2622 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07002623
2624 name = annotation.func.id
2625 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
2626 return name, False, kwargs
2627
2628 def parse_special_symbol(self, symbol):
2629 if self.parameter_state == self.ps_seen_slash:
2630 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
2631
2632 if symbol == '*':
2633 if self.keyword_only:
2634 fail("Function " + self.function.name + " uses '*' more than once.")
2635 self.keyword_only = True
2636 elif symbol == '[':
2637 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
2638 self.parameter_state = self.ps_left_square_before
2639 elif self.parameter_state in (self.ps_required, self.ps_group_after):
2640 self.parameter_state = self.ps_group_after
2641 else:
2642 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2643 self.group += 1
2644 elif symbol == ']':
2645 if not self.group:
2646 fail("Function " + self.function.name + " has a ] without a matching [.")
2647 if not any(p.group == self.group for p in self.function.parameters.values()):
2648 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
2649 self.group -= 1
2650 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
2651 self.parameter_state = self.ps_group_before
2652 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
2653 self.parameter_state = self.ps_right_square_after
2654 else:
2655 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2656 elif symbol == '/':
2657 # ps_required is allowed here, that allows positional-only without option groups
2658 # to work (and have default values!)
2659 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
2660 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2661 if self.keyword_only:
2662 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2663 self.parameter_state = self.ps_seen_slash
2664 # fixup preceeding parameters
2665 for p in self.function.parameters.values():
2666 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
2667 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2668 p.kind = inspect.Parameter.POSITIONAL_ONLY
2669
2670 def state_parameter_docstring_start(self, line):
2671 self.parameter_docstring_indent = len(self.indent.margin)
2672 assert self.indent.depth == 3
2673 return self.next(self.state_parameter_docstring, line)
2674
2675 # every line of the docstring must start with at least F spaces,
2676 # where F > P.
2677 # these F spaces will be stripped.
2678 def state_parameter_docstring(self, line):
2679 stripped = line.strip()
2680 if stripped.startswith('#'):
2681 return
2682
2683 indent = self.indent.measure(line)
2684 if indent < self.parameter_docstring_indent:
2685 self.indent.infer(line)
2686 assert self.indent.depth < 3
2687 if self.indent.depth == 2:
2688 # back to a parameter
2689 return self.next(self.state_parameter, line)
2690 assert self.indent.depth == 1
2691 return self.next(self.state_function_docstring, line)
2692
2693 assert self.function.parameters
2694 last_parameter = next(reversed(list(self.function.parameters.values())))
2695
2696 new_docstring = last_parameter.docstring
2697
2698 if new_docstring:
2699 new_docstring += '\n'
2700 if stripped:
2701 new_docstring += self.indent.dedent(line)
2702
2703 last_parameter.docstring = new_docstring
2704
2705 # the final stanza of the DSL is the docstring.
2706 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07002707 if self.group:
2708 fail("Function " + self.function.name + " has a ] without a matching [.")
2709
2710 stripped = line.strip()
2711 if stripped.startswith('#'):
2712 return
2713
2714 new_docstring = self.function.docstring
2715 if new_docstring:
2716 new_docstring += "\n"
2717 if stripped:
2718 line = self.indent.dedent(line).rstrip()
2719 else:
2720 line = ''
2721 new_docstring += line
2722 self.function.docstring = new_docstring
2723
2724 def format_docstring(self):
2725 f = self.function
2726
2727 add, output = text_accumulator()
2728 parameters = list(f.parameters.values())
2729
2730 ##
2731 ## docstring first line
2732 ##
2733
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002734 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07002735 add('(')
2736
2737 # populate "right_bracket_count" field for every parameter
2738 if parameters:
2739 # for now, the only way Clinic supports positional-only parameters
2740 # is if all of them are positional-only.
2741 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
2742 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
2743 assert all(positional_only_parameters)
2744 for p in parameters:
2745 p.right_bracket_count = abs(p.group)
2746 else:
2747 # don't put any right brackets around non-positional-only parameters, ever.
2748 for p in parameters:
2749 p.right_bracket_count = 0
2750
2751 right_bracket_count = 0
2752
2753 def fix_right_bracket_count(desired):
2754 nonlocal right_bracket_count
2755 s = ''
2756 while right_bracket_count < desired:
2757 s += '['
2758 right_bracket_count += 1
2759 while right_bracket_count > desired:
2760 s += ']'
2761 right_bracket_count -= 1
2762 return s
2763
2764 added_star = False
2765 add_comma = False
2766
2767 for p in parameters:
2768 assert p.name
2769
2770 if p.is_keyword_only() and not added_star:
2771 added_star = True
2772 if add_comma:
2773 add(', ')
2774 add('*')
2775
2776 a = [p.name]
2777 if p.converter.is_optional():
2778 a.append('=')
2779 value = p.converter.default
2780 a.append(p.converter.doc_default)
2781 s = fix_right_bracket_count(p.right_bracket_count)
2782 s += "".join(a)
2783 if add_comma:
2784 add(', ')
2785 add(s)
2786 add_comma = True
2787
2788 add(fix_right_bracket_count(0))
2789 add(')')
2790
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002791 # if f.return_converter.doc_default:
2792 # add(' -> ')
2793 # add(f.return_converter.doc_default)
Larry Hastings31826802013-10-19 00:09:25 -07002794
2795 docstring_first_line = output()
2796
2797 # now fix up the places where the brackets look wrong
2798 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
2799
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002800 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07002801 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002802 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07002803 for p in parameters:
2804 if not p.docstring.strip():
2805 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002806 if spacer_line:
2807 add('\n')
2808 else:
2809 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07002810 add(" ")
2811 add(p.name)
2812 add('\n')
2813 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002814 parameters = output()
2815 if parameters:
2816 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07002817
2818 ##
2819 ## docstring body
2820 ##
2821
2822 docstring = f.docstring.rstrip()
2823 lines = [line.rstrip() for line in docstring.split('\n')]
2824
2825 # Enforce the summary line!
2826 # The first line of a docstring should be a summary of the function.
2827 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
2828 # by itself.
2829 #
2830 # Argument Clinic enforces the following rule:
2831 # * either the docstring is empty,
2832 # * or it must have a summary line.
2833 #
2834 # Guido said Clinic should enforce this:
2835 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
2836
2837 if len(lines) >= 2:
2838 if lines[1]:
2839 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
2840 "Every non-blank function docstring must start with\n" +
2841 "a single line summary followed by an empty line.")
2842 elif len(lines) == 1:
2843 # the docstring is only one line right now--the summary line.
2844 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002845 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07002846 lines.append('')
2847
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002848 parameters_marker_count = len(docstring.split('{parameters}')) - 1
2849 if parameters_marker_count > 1:
2850 fail('You may not specify {parameters} more than once in a docstring!')
2851
2852 if not parameters_marker_count:
2853 # insert after summary line
2854 lines.insert(2, '{parameters}')
2855
2856 # insert at front of docstring
2857 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07002858
2859 docstring = "\n".join(lines)
2860
2861 add(docstring)
2862 docstring = output()
2863
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002864 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07002865 docstring = docstring.rstrip()
2866
2867 return docstring
2868
2869 def state_terminal(self, line):
2870 """
2871 Called when processing the block is done.
2872 """
2873 assert not line
2874
2875 if not self.function:
2876 return
2877
Larry Hastings6d2ea212014-01-05 02:50:45 -08002878 if not self.function.self_converter:
2879 self.function.self_converter = self_converter("self", self.function)
2880
Larry Hastings31826802013-10-19 00:09:25 -07002881 if self.keyword_only:
2882 values = self.function.parameters.values()
2883 if not values:
2884 no_parameter_after_star = True
2885 else:
2886 last_parameter = next(reversed(list(values)))
2887 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
2888 if no_parameter_after_star:
2889 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
2890
2891 # remove trailing whitespace from all parameter docstrings
2892 for name, value in self.function.parameters.items():
2893 if not value:
2894 continue
2895 value.docstring = value.docstring.rstrip()
2896
2897 self.function.docstring = self.format_docstring()
2898
2899
2900# maps strings to callables.
2901# the callable should return an object
2902# that implements the clinic parser
2903# interface (__init__ and parse).
2904#
2905# example parsers:
2906# "clinic", handles the Clinic DSL
2907# "python", handles running Python code
2908#
2909parsers = {'clinic' : DSLParser, 'python': PythonParser}
2910
2911
2912clinic = None
2913
2914
2915def main(argv):
2916 import sys
2917
2918 if sys.version_info.major < 3 or sys.version_info.minor < 3:
2919 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
2920
2921 import argparse
2922 cmdline = argparse.ArgumentParser()
2923 cmdline.add_argument("-f", "--force", action='store_true')
2924 cmdline.add_argument("-o", "--output", type=str)
2925 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002926 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07002927 cmdline.add_argument("filename", type=str, nargs="*")
2928 ns = cmdline.parse_args(argv)
2929
2930 if ns.converters:
2931 if ns.filename:
2932 print("Usage error: can't specify --converters and a filename at the same time.")
2933 print()
2934 cmdline.print_usage()
2935 sys.exit(-1)
2936 converters = []
2937 return_converters = []
2938 ignored = set("""
2939 add_c_converter
2940 add_c_return_converter
2941 add_default_legacy_c_converter
2942 add_legacy_c_converter
2943 """.strip().split())
2944 module = globals()
2945 for name in module:
2946 for suffix, ids in (
2947 ("_return_converter", return_converters),
2948 ("_converter", converters),
2949 ):
2950 if name in ignored:
2951 continue
2952 if name.endswith(suffix):
2953 ids.append((name, name[:-len(suffix)]))
2954 break
2955 print()
2956
2957 print("Legacy converters:")
2958 legacy = sorted(legacy_converters)
2959 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
2960 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
2961 print()
2962
2963 for title, attribute, ids in (
2964 ("Converters", 'converter_init', converters),
2965 ("Return converters", 'return_converter_init', return_converters),
2966 ):
2967 print(title + ":")
2968 longest = -1
2969 for name, short_name in ids:
2970 longest = max(longest, len(short_name))
2971 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
2972 cls = module[name]
2973 callable = getattr(cls, attribute, None)
2974 if not callable:
2975 continue
2976 signature = inspect.signature(callable)
2977 parameters = []
2978 for parameter_name, parameter in signature.parameters.items():
2979 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2980 if parameter.default != inspect.Parameter.empty:
2981 s = '{}={!r}'.format(parameter_name, parameter.default)
2982 else:
2983 s = parameter_name
2984 parameters.append(s)
2985 print(' {}({})'.format(short_name, ', '.join(parameters)))
2986 # add_comma = False
2987 # for parameter_name, parameter in signature.parameters.items():
2988 # if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2989 # if add_comma:
2990 # parameters.append(', ')
2991 # else:
2992 # add_comma = True
2993 # s = parameter_name
2994 # if parameter.default != inspect.Parameter.empty:
2995 # s += '=' + repr(parameter.default)
2996 # parameters.append(s)
2997 # parameters.append(')')
2998
2999 # print(" ", short_name + "".join(parameters))
3000 print()
Larry Hastings78cf85c2014-01-04 12:44:57 -08003001 print("All converters also accept (doc_default=None, required=False, annotation=None).")
Larry Hastings31826802013-10-19 00:09:25 -07003002 print("All return converters also accept (doc_default=None).")
3003 sys.exit(0)
3004
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003005 if ns.make:
3006 if ns.output or ns.filename:
3007 print("Usage error: can't use -o or filenames with --make.")
3008 print()
3009 cmdline.print_usage()
3010 sys.exit(-1)
3011 for root, dirs, files in os.walk('.'):
3012 for rcs_dir in ('.svn', '.git', '.hg'):
3013 if rcs_dir in dirs:
3014 dirs.remove(rcs_dir)
3015 for filename in files:
3016 if not filename.endswith('.c'):
3017 continue
3018 path = os.path.join(root, filename)
3019 parse_file(path, verify=not ns.force)
3020 return
3021
Larry Hastings31826802013-10-19 00:09:25 -07003022 if not ns.filename:
3023 cmdline.print_usage()
3024 sys.exit(-1)
3025
3026 if ns.output and len(ns.filename) > 1:
3027 print("Usage error: can't use -o with multiple filenames.")
3028 print()
3029 cmdline.print_usage()
3030 sys.exit(-1)
3031
3032 for filename in ns.filename:
3033 parse_file(filename, output=ns.output, verify=not ns.force)
3034
3035
3036if __name__ == "__main__":
3037 sys.exit(main(sys.argv[1:]))