blob: ed59f05b1ecd6f99577a3042443701b09de39123 [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
24
Larry Hastings31826802013-10-19 00:09:25 -070025# TODO:
Larry Hastings31826802013-10-19 00:09:25 -070026#
27# soon:
28#
29# * allow mixing any two of {positional-only, positional-or-keyword,
30# keyword-only}
31# * dict constructor uses positional-only and keyword-only
32# * max and min use positional only with an optional group
33# and keyword-only
34#
Larry Hastings31826802013-10-19 00:09:25 -070035
Larry Hastingsebdcb502013-11-23 14:54:00 -080036version = '1'
37
Larry Hastings31826802013-10-19 00:09:25 -070038_empty = inspect._empty
39_void = inspect._void
40
Larry Hastings4a55fc52014-01-12 11:09:57 -080041NoneType = type(None)
Larry Hastings31826802013-10-19 00:09:25 -070042
43class Unspecified:
44 def __repr__(self):
45 return '<Unspecified>'
46
47unspecified = Unspecified()
48
49
50class Null:
51 def __repr__(self):
52 return '<Null>'
53
54NULL = Null()
55
56
57def _text_accumulator():
58 text = []
59 def output():
60 s = ''.join(text)
61 text.clear()
62 return s
63 return text, text.append, output
64
65
66def text_accumulator():
67 """
68 Creates a simple text accumulator / joiner.
69
70 Returns a pair of callables:
71 append, output
72 "append" appends a string to the accumulator.
73 "output" returns the contents of the accumulator
74 joined together (''.join(accumulator)) and
75 empties the accumulator.
76 """
77 text, append, output = _text_accumulator()
78 return append, output
79
80
81def fail(*args, filename=None, line_number=None):
82 joined = " ".join([str(a) for a in args])
83 add, output = text_accumulator()
84 add("Error")
85 if clinic:
86 if filename is None:
87 filename = clinic.filename
88 if clinic.block_parser and (line_number is None):
89 line_number = clinic.block_parser.line_number
90 if filename is not None:
91 add(' in file "' + filename + '"')
92 if line_number is not None:
93 add(" on line " + str(line_number))
94 add(':\n')
95 add(joined)
96 print(output())
97 sys.exit(-1)
98
99
100
101def quoted_for_c_string(s):
102 for old, new in (
103 ('"', '\\"'),
104 ("'", "\\'"),
105 ):
106 s = s.replace(old, new)
107 return s
108
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700109is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
110
111def is_legal_py_identifier(s):
112 return all(is_legal_c_identifier(field) for field in s.split('.'))
113
Larry Hastings8666e652014-01-12 14:12:59 -0800114# though it's called c_keywords, really it's a list of parameter names
115# that are okay in Python but aren't a good idea in C. so if they're used
116# Argument Clinic will add "_value" to the end of the name in C.
117# (We added "args", "type", "module", "self", "cls", and "null"
118# just to be safe, even though they're not C keywords.)
Larry Hastings31826802013-10-19 00:09:25 -0700119c_keywords = set("""
Larry Hastings8666e652014-01-12 14:12:59 -0800120args asm auto break case char cls const continue default do double
Larry Hastingsed4a1c52013-11-18 09:32:13 -0800121else enum extern float for goto if inline int long module null
122register return self short signed sizeof static struct switch
Larry Hastings8666e652014-01-12 14:12:59 -0800123type typedef typeof union unsigned void volatile while
Larry Hastings31826802013-10-19 00:09:25 -0700124""".strip().split())
125
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700126def ensure_legal_c_identifier(s):
127 # for now, just complain if what we're given isn't legal
128 if not is_legal_c_identifier(s):
129 fail("Illegal C identifier: {}".format(s))
130 # but if we picked a C keyword, pick something else
Larry Hastings31826802013-10-19 00:09:25 -0700131 if s in c_keywords:
132 return s + "_value"
133 return s
134
135def rstrip_lines(s):
136 text, add, output = _text_accumulator()
137 for line in s.split('\n'):
138 add(line.rstrip())
139 add('\n')
140 text.pop()
141 return output()
142
143def linear_format(s, **kwargs):
144 """
145 Perform str.format-like substitution, except:
146 * The strings substituted must be on lines by
147 themselves. (This line is the "source line".)
148 * If the substitution text is empty, the source line
149 is removed in the output.
150 * If the substitution text is not empty:
151 * Each line of the substituted text is indented
152 by the indent of the source line.
153 * A newline will be added to the end.
154 """
155
156 add, output = text_accumulator()
157 for line in s.split('\n'):
158 indent, curly, trailing = line.partition('{')
159 if not curly:
160 add(line)
161 add('\n')
162 continue
163
164 name, curl, trailing = trailing.partition('}')
165 if not curly or name not in kwargs:
166 add(line)
167 add('\n')
168 continue
169
170 if trailing:
171 fail("Text found after {" + name + "} block marker! It must be on a line by itself.")
172 if indent.strip():
173 fail("Non-whitespace characters found before {" + name + "} block marker! It must be on a line by itself.")
174
175 value = kwargs[name]
176 if not value:
177 continue
178
179 value = textwrap.indent(rstrip_lines(value), indent)
180 add(value)
181 add('\n')
182
183 return output()[:-1]
184
Larry Hastingsebdcb502013-11-23 14:54:00 -0800185def version_splitter(s):
186 """Splits a version string into a tuple of integers.
187
188 The following ASCII characters are allowed, and employ
189 the following conversions:
190 a -> -3
191 b -> -2
192 c -> -1
193 (This permits Python-style version strings such as "1.4b3".)
194 """
195 version = []
196 accumulator = []
197 def flush():
198 if not accumulator:
199 raise ValueError('Malformed version string: ' + repr(s))
200 version.append(int(''.join(accumulator)))
201 accumulator.clear()
202
203 for c in s:
204 if c.isdigit():
205 accumulator.append(c)
206 elif c == '.':
207 flush()
208 elif c in 'abc':
209 flush()
210 version.append('abc'.index(c) - 3)
211 else:
212 raise ValueError('Illegal character ' + repr(c) + ' in version string ' + repr(s))
213 flush()
214 return tuple(version)
215
216def version_comparitor(version1, version2):
217 iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
218 for i, (a, b) in enumerate(iterator):
219 if a < b:
220 return -1
221 if a > b:
222 return 1
223 return 0
224
Larry Hastings31826802013-10-19 00:09:25 -0700225
226class CRenderData:
227 def __init__(self):
228
229 # The C statements to declare variables.
230 # Should be full lines with \n eol characters.
231 self.declarations = []
232
233 # The C statements required to initialize the variables before the parse call.
234 # Should be full lines with \n eol characters.
235 self.initializers = []
236
237 # The entries for the "keywords" array for PyArg_ParseTuple.
238 # Should be individual strings representing the names.
239 self.keywords = []
240
241 # The "format units" for PyArg_ParseTuple.
242 # Should be individual strings that will get
243 self.format_units = []
244
245 # The varargs arguments for PyArg_ParseTuple.
246 self.parse_arguments = []
247
248 # The parameter declarations for the impl function.
249 self.impl_parameters = []
250
251 # The arguments to the impl function at the time it's called.
252 self.impl_arguments = []
253
254 # For return converters: the name of the variable that
255 # should receive the value returned by the impl.
256 self.return_value = "return_value"
257
258 # For return converters: the code to convert the return
259 # value from the parse function. This is also where
260 # you should check the _return_value for errors, and
261 # "goto exit" if there are any.
262 self.return_conversion = []
263
264 # The C statements required to clean up after the impl call.
265 self.cleanup = []
266
267
268class Language(metaclass=abc.ABCMeta):
269
270 start_line = ""
271 body_prefix = ""
272 stop_line = ""
273 checksum_line = ""
274
275 @abc.abstractmethod
276 def render(self, block):
277 pass
278
279 def validate(self):
280 def assert_only_one(field, token='dsl_name'):
281 line = getattr(self, field)
282 token = '{' + token + '}'
283 if len(line.split(token)) != 2:
284 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
285 assert_only_one('start_line')
286 assert_only_one('stop_line')
287 assert_only_one('checksum_line')
288 assert_only_one('checksum_line', 'checksum')
289
290 if len(self.body_prefix.split('{dsl_name}')) >= 3:
291 fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
292
293
294
295class PythonLanguage(Language):
296
297 language = 'Python'
Larry Hastings61272b72014-01-07 12:41:53 -0800298 start_line = "#/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700299 body_prefix = "#"
Larry Hastings61272b72014-01-07 12:41:53 -0800300 stop_line = "#[{dsl_name} start generated code]*/"
301 checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700302
303
304def permute_left_option_groups(l):
305 """
306 Given [1, 2, 3], should yield:
307 ()
308 (3,)
309 (2, 3)
310 (1, 2, 3)
311 """
312 yield tuple()
313 accumulator = []
314 for group in reversed(l):
315 accumulator = list(group) + accumulator
316 yield tuple(accumulator)
317
318
319def permute_right_option_groups(l):
320 """
321 Given [1, 2, 3], should yield:
322 ()
323 (1,)
324 (1, 2)
325 (1, 2, 3)
326 """
327 yield tuple()
328 accumulator = []
329 for group in l:
330 accumulator.extend(group)
331 yield tuple(accumulator)
332
333
334def permute_optional_groups(left, required, right):
335 """
336 Generator function that computes the set of acceptable
337 argument lists for the provided iterables of
338 argument groups. (Actually it generates a tuple of tuples.)
339
340 Algorithm: prefer left options over right options.
341
342 If required is empty, left must also be empty.
343 """
344 required = tuple(required)
345 result = []
346
347 if not required:
348 assert not left
349
350 accumulator = []
351 counts = set()
352 for r in permute_right_option_groups(right):
353 for l in permute_left_option_groups(left):
354 t = l + required + r
355 if len(t) in counts:
356 continue
357 counts.add(len(t))
358 accumulator.append(t)
359
360 accumulator.sort(key=len)
361 return tuple(accumulator)
362
363
364class CLanguage(Language):
365
Larry Hastings61272b72014-01-07 12:41:53 -0800366 body_prefix = "#"
Larry Hastings31826802013-10-19 00:09:25 -0700367 language = 'C'
Larry Hastings61272b72014-01-07 12:41:53 -0800368 start_line = "/*[{dsl_name} input]"
Larry Hastings31826802013-10-19 00:09:25 -0700369 body_prefix = ""
Larry Hastings61272b72014-01-07 12:41:53 -0800370 stop_line = "[{dsl_name} start generated code]*/"
371 checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/"
Larry Hastings31826802013-10-19 00:09:25 -0700372
373 def render(self, signatures):
374 function = None
375 for o in signatures:
376 if isinstance(o, Function):
377 if function:
378 fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o))
379 function = o
380 return self.render_function(function)
381
382 def docstring_for_c_string(self, f):
383 text, add, output = _text_accumulator()
384 # turn docstring into a properly quoted C string
385 for line in f.docstring.split('\n'):
386 add('"')
387 add(quoted_for_c_string(line))
388 add('\\n"\n')
389
390 text.pop()
391 add('"')
392 return ''.join(text)
393
394 impl_prototype_template = "{c_basename}_impl({impl_parameters})"
395
396 @staticmethod
397 def template_base(*args):
Larry Hastings8666e652014-01-12 14:12:59 -0800398 # HACK suppress methoddef define for METHOD_NEW and METHOD_INIT
399 base = """
Larry Hastings31826802013-10-19 00:09:25 -0700400PyDoc_STRVAR({c_basename}__doc__,
401{docstring});
Larry Hastings8666e652014-01-12 14:12:59 -0800402"""
Larry Hastings31826802013-10-19 00:09:25 -0700403
Larry Hastings8666e652014-01-12 14:12:59 -0800404 if args[-1] == None:
405 return base
406
407 flags = '|'.join(f for f in args if f)
408 return base + """
Larry Hastings31826802013-10-19 00:09:25 -0700409#define {methoddef_name} \\
Larry Hastingsebdcb502013-11-23 14:54:00 -0800410 {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
411""".replace('{methoddef_flags}', flags)
Larry Hastings31826802013-10-19 00:09:25 -0700412
Larry Hastingsebdcb502013-11-23 14:54:00 -0800413 def meth_noargs_template(self, methoddef_flags=""):
414 return self.template_base("METH_NOARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700415static {impl_return_type}
416{impl_prototype};
417
418static PyObject *
Larry Hastings3cceb382014-01-04 11:09:09 -0800419{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
Larry Hastings31826802013-10-19 00:09:25 -0700420{{
421 PyObject *return_value = NULL;
422 {declarations}
423 {initializers}
424
425 {return_value} = {c_basename}_impl({impl_arguments});
426 {return_conversion}
427
428{exit_label}
429 {cleanup}
430 return return_value;
431}}
432
433static {impl_return_type}
434{impl_prototype}
435"""
436
Larry Hastingsebdcb502013-11-23 14:54:00 -0800437 def meth_o_template(self, methoddef_flags=""):
438 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700439static PyObject *
440{c_basename}({impl_parameters})
441"""
442
Larry Hastingsebdcb502013-11-23 14:54:00 -0800443 def meth_o_return_converter_template(self, methoddef_flags=""):
444 return self.template_base("METH_O", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700445static {impl_return_type}
446{impl_prototype};
447
448static PyObject *
449{c_basename}({impl_parameters})
450{{
451 PyObject *return_value = NULL;
452 {declarations}
453 {initializers}
454 _return_value = {c_basename}_impl({impl_arguments});
455 {return_conversion}
456
457{exit_label}
458 {cleanup}
459 return return_value;
460}}
461
462static {impl_return_type}
463{impl_prototype}
464"""
465
Larry Hastingsebdcb502013-11-23 14:54:00 -0800466 def option_group_template(self, methoddef_flags=""):
467 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700468static {impl_return_type}
469{impl_prototype};
470
471static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800472{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700473{{
474 PyObject *return_value = NULL;
475 {declarations}
476 {initializers}
477
478 {option_group_parsing}
479 {return_value} = {c_basename}_impl({impl_arguments});
480 {return_conversion}
481
482{exit_label}
483 {cleanup}
484 return return_value;
485}}
486
487static {impl_return_type}
488{impl_prototype}
489"""
490
Larry Hastingsebdcb502013-11-23 14:54:00 -0800491 def keywords_template(self, methoddef_flags=""):
492 return self.template_base("METH_VARARGS|METH_KEYWORDS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700493static {impl_return_type}
494{impl_prototype};
495
496static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800497{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
Larry Hastings31826802013-10-19 00:09:25 -0700498{{
499 PyObject *return_value = NULL;
500 static char *_keywords[] = {{{keywords}, NULL}};
501 {declarations}
502 {initializers}
503
504 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
505 "{format_units}:{name}", _keywords,
506 {parse_arguments}))
507 goto exit;
508 {return_value} = {c_basename}_impl({impl_arguments});
509 {return_conversion}
510
511{exit_label}
512 {cleanup}
513 return return_value;
514}}
515
516static {impl_return_type}
517{impl_prototype}
518"""
519
Larry Hastingsebdcb502013-11-23 14:54:00 -0800520 def positional_only_template(self, methoddef_flags=""):
521 return self.template_base("METH_VARARGS", methoddef_flags) + """
Larry Hastings31826802013-10-19 00:09:25 -0700522static {impl_return_type}
523{impl_prototype};
524
525static PyObject *
Larry Hastingsebdcb502013-11-23 14:54:00 -0800526{c_basename}({self_type}{self_name}, PyObject *args)
Larry Hastings31826802013-10-19 00:09:25 -0700527{{
528 PyObject *return_value = NULL;
529 {declarations}
530 {initializers}
531
532 if (!PyArg_ParseTuple(args,
533 "{format_units}:{name}",
534 {parse_arguments}))
535 goto exit;
536 {return_value} = {c_basename}_impl({impl_arguments});
537 {return_conversion}
538
539{exit_label}
540 {cleanup}
541 return return_value;
542}}
543
544static {impl_return_type}
545{impl_prototype}
546"""
547
548 @staticmethod
549 def group_to_variable_name(group):
550 adjective = "left_" if group < 0 else "right_"
551 return "group_" + adjective + str(abs(group))
552
553 def render_option_group_parsing(self, f, template_dict):
554 # positional only, grouped, optional arguments!
555 # can be optional on the left or right.
556 # here's an example:
557 #
558 # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ]
559 #
560 # Here group D are required, and all other groups are optional.
561 # (Group D's "group" is actually None.)
562 # We can figure out which sets of arguments we have based on
563 # how many arguments are in the tuple.
564 #
565 # Note that you need to count up on both sides. For example,
566 # you could have groups C+D, or C+D+E, or C+D+E+F.
567 #
568 # What if the number of arguments leads us to an ambiguous result?
569 # Clinic prefers groups on the left. So in the above example,
570 # five arguments would map to B+C, not C+D.
571
572 add, output = text_accumulator()
573 parameters = list(f.parameters.values())
574
575 groups = []
576 group = None
577 left = []
578 right = []
579 required = []
580 last = unspecified
581
582 for p in parameters:
583 group_id = p.group
584 if group_id != last:
585 last = group_id
586 group = []
587 if group_id < 0:
588 left.append(group)
589 elif group_id == 0:
590 group = required
591 else:
592 right.append(group)
593 group.append(p)
594
595 count_min = sys.maxsize
596 count_max = -1
597
598 add("switch (PyTuple_Size(args)) {{\n")
599 for subset in permute_optional_groups(left, required, right):
600 count = len(subset)
601 count_min = min(count_min, count)
602 count_max = max(count_max, count)
603
Larry Hastings583baa82014-01-12 08:49:30 -0800604 if count == 0:
605 add(""" case 0:
606 break;
607""")
608 continue
609
Larry Hastings31826802013-10-19 00:09:25 -0700610 group_ids = {p.group for p in subset} # eliminate duplicates
611 d = {}
612 d['count'] = count
613 d['name'] = f.name
614 d['groups'] = sorted(group_ids)
615 d['format_units'] = "".join(p.converter.format_unit for p in subset)
616
617 parse_arguments = []
618 for p in subset:
619 p.converter.parse_argument(parse_arguments)
620 d['parse_arguments'] = ", ".join(parse_arguments)
621
622 group_ids.discard(0)
623 lines = [self.group_to_variable_name(g) + " = 1;" for g in group_ids]
624 lines = "\n".join(lines)
625
626 s = """
627 case {count}:
628 if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
629 return NULL;
630 {group_booleans}
631 break;
632"""[1:]
633 s = linear_format(s, group_booleans=lines)
634 s = s.format_map(d)
635 add(s)
636
637 add(" default:\n")
638 s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n'
639 add(s.format(f.full_name, count_min, count_max))
640 add(' return NULL;\n')
641 add("}}")
642 template_dict['option_group_parsing'] = output()
643
644 def render_function(self, f):
645 if not f:
646 return ""
647
648 add, output = text_accumulator()
649 data = CRenderData()
650
Larry Hastings31826802013-10-19 00:09:25 -0700651 parameters = list(f.parameters.values())
652 converters = [p.converter for p in parameters]
653
654 template_dict = {}
655
656 full_name = f.full_name
657 template_dict['full_name'] = full_name
658
659 name = full_name.rpartition('.')[2]
660 template_dict['name'] = name
661
Larry Hastings8666e652014-01-12 14:12:59 -0800662 if f.c_basename:
663 c_basename = f.c_basename
664 else:
665 fields = full_name.split(".")
666 if fields[-1] == '__new__':
667 fields.pop()
668 c_basename = "_".join(fields)
Larry Hastings31826802013-10-19 00:09:25 -0700669 template_dict['c_basename'] = c_basename
670
671 methoddef_name = "{}_METHODDEF".format(c_basename.upper())
672 template_dict['methoddef_name'] = methoddef_name
673
674 template_dict['docstring'] = self.docstring_for_c_string(f)
675
Larry Hastings31826802013-10-19 00:09:25 -0700676 positional = has_option_groups = False
677
678 if parameters:
679 last_group = 0
680
681 for p in parameters:
682 c = p.converter
683
684 # insert group variable
685 group = p.group
686 if last_group != group:
687 last_group = group
688 if group:
689 group_name = self.group_to_variable_name(group)
690 data.impl_arguments.append(group_name)
691 data.declarations.append("int " + group_name + " = 0;")
692 data.impl_parameters.append("int " + group_name)
693 has_option_groups = True
694 c.render(p, data)
695
696 positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY
Larry Hastings4a55fc52014-01-12 11:09:57 -0800697 if has_option_groups and (not positional):
698 fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').")
Larry Hastings31826802013-10-19 00:09:25 -0700699
Larry Hastingsebdcb502013-11-23 14:54:00 -0800700 # now insert our "self" (or whatever) parameters
701 # (we deliberately don't call render on self converters)
702 stock_self = self_converter('self', f)
703 template_dict['self_name'] = stock_self.name
704 template_dict['self_type'] = stock_self.type
705 data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name)
706 if f.self_converter.type != stock_self.type:
707 self_cast = '(' + f.self_converter.type + ')'
708 else:
709 self_cast = ''
710 data.impl_arguments.insert(0, self_cast + stock_self.name)
711
Larry Hastings31826802013-10-19 00:09:25 -0700712 f.return_converter.render(f, data)
713 template_dict['impl_return_type'] = f.return_converter.type
714
715 template_dict['declarations'] = "\n".join(data.declarations)
716 template_dict['initializers'] = "\n\n".join(data.initializers)
717 template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
718 template_dict['format_units'] = ''.join(data.format_units)
719 template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
720 template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
721 template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
722 template_dict['return_conversion'] = "".join(data.return_conversion).rstrip()
723 template_dict['cleanup'] = "".join(data.cleanup)
724 template_dict['return_value'] = data.return_value
725
726 template_dict['impl_prototype'] = self.impl_prototype_template.format_map(template_dict)
727
728 default_return_converter = (not f.return_converter or
729 f.return_converter.type == 'PyObject *')
730
731 if not parameters:
Larry Hastings3cceb382014-01-04 11:09:09 -0800732 template = self.meth_noargs_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700733 elif (len(parameters) == 1 and
734 parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
735 not converters[0].is_optional() and
736 isinstance(converters[0], object_converter) and
737 converters[0].format_unit == 'O'):
738 if default_return_converter:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800739 template = self.meth_o_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700740 else:
741 # HACK
742 # we're using "impl_parameters" for the
743 # non-impl function, because that works
744 # better for METH_O. but that means we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800745 # must supress actually declaring the
Larry Hastings31826802013-10-19 00:09:25 -0700746 # impl's parameters as variables in the
747 # non-impl. but since it's METH_O, we
Larry Hastingsebdcb502013-11-23 14:54:00 -0800748 # only have one anyway, so
749 # we don't have any problem finding it.
Larry Hastings31826802013-10-19 00:09:25 -0700750 declarations_copy = list(data.declarations)
751 before, pyobject, after = declarations_copy[0].partition('PyObject *')
752 assert not before, "hack failed, see comment"
753 assert pyobject, "hack failed, see comment"
754 assert after and after[0].isalpha(), "hack failed, see comment"
755 del declarations_copy[0]
756 template_dict['declarations'] = "\n".join(declarations_copy)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800757 template = self.meth_o_return_converter_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700758 elif has_option_groups:
759 self.render_option_group_parsing(f, template_dict)
Larry Hastingsebdcb502013-11-23 14:54:00 -0800760 template = self.option_group_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700761 template = linear_format(template,
762 option_group_parsing=template_dict['option_group_parsing'])
763 elif positional:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800764 template = self.positional_only_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700765 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -0800766 template = self.keywords_template(f.methoddef_flags)
Larry Hastings31826802013-10-19 00:09:25 -0700767
768 template = linear_format(template,
769 declarations=template_dict['declarations'],
770 return_conversion=template_dict['return_conversion'],
771 initializers=template_dict['initializers'],
772 cleanup=template_dict['cleanup'],
773 )
774
775 # Only generate the "exit:" label
776 # if we have any gotos
777 need_exit_label = "goto exit;" in template
778 template = linear_format(template,
779 exit_label="exit:" if need_exit_label else ''
780 )
781
782 return template.format_map(template_dict)
783
784
785@contextlib.contextmanager
786def OverrideStdioWith(stdout):
787 saved_stdout = sys.stdout
788 sys.stdout = stdout
789 try:
790 yield
791 finally:
792 assert sys.stdout is stdout
793 sys.stdout = saved_stdout
794
795
796def create_regex(before, after):
797 """Create an re object for matching marker lines."""
798 pattern = r'^{}(\w+){}$'
799 return re.compile(pattern.format(re.escape(before), re.escape(after)))
800
801
802class Block:
803 r"""
804 Represents a single block of text embedded in
805 another file. If dsl_name is None, the block represents
806 verbatim text, raw original text from the file, in
807 which case "input" will be the only non-false member.
808 If dsl_name is not None, the block represents a Clinic
809 block.
810
811 input is always str, with embedded \n characters.
812 input represents the original text from the file;
813 if it's a Clinic block, it is the original text with
814 the body_prefix and redundant leading whitespace removed.
815
816 dsl_name is either str or None. If str, it's the text
817 found on the start line of the block between the square
818 brackets.
819
820 signatures is either list or None. If it's a list,
821 it may only contain clinic.Module, clinic.Class, and
822 clinic.Function objects. At the moment it should
823 contain at most one of each.
824
825 output is either str or None. If str, it's the output
826 from this block, with embedded '\n' characters.
827
828 indent is either str or None. It's the leading whitespace
829 that was found on every line of input. (If body_prefix is
830 not empty, this is the indent *after* removing the
831 body_prefix.)
832
833 preindent is either str or None. It's the whitespace that
834 was found in front of every line of input *before* the
835 "body_prefix" (see the Language object). If body_prefix
836 is empty, preindent must always be empty too.
837
838 To illustrate indent and preindent: Assume that '_'
839 represents whitespace. If the block processed was in a
840 Python file, and looked like this:
841 ____#/*[python]
842 ____#__for a in range(20):
843 ____#____print(a)
844 ____#[python]*/
845 "preindent" would be "____" and "indent" would be "__".
846
847 """
848 def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''):
849 assert isinstance(input, str)
850 self.input = input
851 self.dsl_name = dsl_name
852 self.signatures = signatures or []
853 self.output = output
854 self.indent = indent
855 self.preindent = preindent
856
857
858class BlockParser:
859 """
860 Block-oriented parser for Argument Clinic.
861 Iterator, yields Block objects.
862 """
863
864 def __init__(self, input, language, *, verify=True):
865 """
866 "input" should be a str object
867 with embedded \n characters.
868
869 "language" should be a Language object.
870 """
871 language.validate()
872
873 self.input = collections.deque(reversed(input.splitlines(keepends=True)))
874 self.block_start_line_number = self.line_number = 0
875
876 self.language = language
877 before, _, after = language.start_line.partition('{dsl_name}')
878 assert _ == '{dsl_name}'
879 self.start_re = create_regex(before, after)
880 self.verify = verify
881 self.last_checksum_re = None
882 self.last_dsl_name = None
883 self.dsl_name = None
884
885 def __iter__(self):
886 return self
887
888 def __next__(self):
889 if not self.input:
890 raise StopIteration
891
892 if self.dsl_name:
893 return_value = self.parse_clinic_block(self.dsl_name)
894 self.dsl_name = None
895 return return_value
896 return self.parse_verbatim_block()
897
898 def is_start_line(self, line):
899 match = self.start_re.match(line.lstrip())
900 return match.group(1) if match else None
901
902 def _line(self):
903 self.line_number += 1
904 return self.input.pop()
905
906 def parse_verbatim_block(self):
907 add, output = text_accumulator()
908 self.block_start_line_number = self.line_number
909
910 while self.input:
911 line = self._line()
912 dsl_name = self.is_start_line(line)
913 if dsl_name:
914 self.dsl_name = dsl_name
915 break
916 add(line)
917
918 return Block(output())
919
920 def parse_clinic_block(self, dsl_name):
921 input_add, input_output = text_accumulator()
922 self.block_start_line_number = self.line_number + 1
Larry Hastings90261132014-01-07 12:21:08 -0800923 stop_line = self.language.stop_line.format(dsl_name=dsl_name)
Larry Hastings31826802013-10-19 00:09:25 -0700924 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
925
Larry Hastings90261132014-01-07 12:21:08 -0800926 def is_stop_line(line):
927 # make sure to recognize stop line even if it
928 # doesn't end with EOL (it could be the very end of the file)
929 if not line.startswith(stop_line):
930 return False
931 remainder = line[len(stop_line):]
932 return (not remainder) or remainder.isspace()
933
Larry Hastings31826802013-10-19 00:09:25 -0700934 # consume body of program
935 while self.input:
936 line = self._line()
Larry Hastings90261132014-01-07 12:21:08 -0800937 if is_stop_line(line) or self.is_start_line(line):
Larry Hastings31826802013-10-19 00:09:25 -0700938 break
939 if body_prefix:
940 line = line.lstrip()
941 assert line.startswith(body_prefix)
942 line = line[len(body_prefix):]
943 input_add(line)
944
945 # consume output and checksum line, if present.
946 if self.last_dsl_name == dsl_name:
947 checksum_re = self.last_checksum_re
948 else:
949 before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}')
950 assert _ == '{checksum}'
951 checksum_re = create_regex(before, after)
952 self.last_dsl_name = dsl_name
953 self.last_checksum_re = checksum_re
954
955 # scan forward for checksum line
956 output_add, output_output = text_accumulator()
957 checksum = None
958 while self.input:
959 line = self._line()
960 match = checksum_re.match(line.lstrip())
961 checksum = match.group(1) if match else None
962 if checksum:
963 break
964 output_add(line)
965 if self.is_start_line(line):
966 break
967
Larry Hastingsef3b1fb2013-10-22 23:26:23 -0700968 output = output_output()
Larry Hastings31826802013-10-19 00:09:25 -0700969 if checksum:
Larry Hastings31826802013-10-19 00:09:25 -0700970 if self.verify:
971 computed = compute_checksum(output)
972 if checksum != computed:
Antoine Pitroucc1d31e2014-01-14 20:52:01 +0100973 fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n"
974 "Suggested fix: remove all generated code including "
975 "the end marker, or use the '-f' option."
976 .format(checksum, computed))
Larry Hastings31826802013-10-19 00:09:25 -0700977 else:
978 # put back output
Larry Hastingseb31e9d2014-01-06 11:10:08 -0800979 output_lines = output.splitlines(keepends=True)
980 self.line_number -= len(output_lines)
981 self.input.extend(reversed(output_lines))
Larry Hastings31826802013-10-19 00:09:25 -0700982 output = None
983
984 return Block(input_output(), dsl_name, output=output)
985
986
987class BlockPrinter:
988
989 def __init__(self, language, f=None):
990 self.language = language
991 self.f = f or io.StringIO()
992
993 def print_block(self, block):
994 input = block.input
995 output = block.output
996 dsl_name = block.dsl_name
997 write = self.f.write
998
Larry Hastings31826802013-10-19 00:09:25 -0700999 assert not ((dsl_name == None) ^ (output == None)), "you must specify dsl_name and output together, dsl_name " + repr(dsl_name)
1000
1001 if not dsl_name:
1002 write(input)
1003 return
1004
1005 write(self.language.start_line.format(dsl_name=dsl_name))
1006 write("\n")
1007
1008 body_prefix = self.language.body_prefix.format(dsl_name=dsl_name)
1009 if not body_prefix:
1010 write(input)
1011 else:
1012 for line in input.split('\n'):
1013 write(body_prefix)
1014 write(line)
1015 write("\n")
1016
1017 write(self.language.stop_line.format(dsl_name=dsl_name))
1018 write("\n")
1019
1020 output = block.output
1021 if output:
1022 write(output)
1023 if not output.endswith('\n'):
1024 write('\n')
1025
1026 write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output)))
1027 write("\n")
1028
1029
1030# maps strings to Language objects.
1031# "languages" maps the name of the language ("C", "Python").
1032# "extensions" maps the file extension ("c", "py").
1033languages = { 'C': CLanguage, 'Python': PythonLanguage }
Larry Hastings6d2ea212014-01-05 02:50:45 -08001034extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() }
1035extensions['py'] = PythonLanguage
Larry Hastings31826802013-10-19 00:09:25 -07001036
1037
1038# maps strings to callables.
1039# these callables must be of the form:
1040# def foo(name, default, *, ...)
1041# The callable may have any number of keyword-only parameters.
1042# The callable must return a CConverter object.
1043# The callable should not call builtins.print.
1044converters = {}
1045
1046# maps strings to callables.
1047# these callables follow the same rules as those for "converters" above.
1048# note however that they will never be called with keyword-only parameters.
1049legacy_converters = {}
1050
1051
1052# maps strings to callables.
1053# these callables must be of the form:
1054# def foo(*, ...)
1055# The callable may have any number of keyword-only parameters.
1056# The callable must return a CConverter object.
1057# The callable should not call builtins.print.
1058return_converters = {}
1059
1060class Clinic:
1061 def __init__(self, language, printer=None, *, verify=True, filename=None):
1062 # maps strings to Parser objects.
1063 # (instantiated from the "parsers" global.)
1064 self.parsers = {}
1065 self.language = language
1066 self.printer = printer or BlockPrinter(language)
1067 self.verify = verify
1068 self.filename = filename
1069 self.modules = collections.OrderedDict()
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001070 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -07001071
1072 global clinic
1073 clinic = self
1074
1075 def parse(self, input):
1076 printer = self.printer
1077 self.block_parser = BlockParser(input, self.language, verify=self.verify)
1078 for block in self.block_parser:
1079 dsl_name = block.dsl_name
1080 if dsl_name:
1081 if dsl_name not in self.parsers:
1082 assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name)
1083 self.parsers[dsl_name] = parsers[dsl_name](self)
1084 parser = self.parsers[dsl_name]
1085 parser.parse(block)
1086 printer.print_block(block)
1087 return printer.f.getvalue()
1088
1089 def _module_and_class(self, fields):
1090 """
1091 fields should be an iterable of field names.
1092 returns a tuple of (module, class).
1093 the module object could actually be self (a clinic object).
1094 this function is only ever used to find the parent of where
1095 a new class/module should go.
1096 """
1097 in_classes = False
1098 parent = module = self
1099 cls = None
1100 so_far = []
1101
1102 for field in fields:
1103 so_far.append(field)
1104 if not in_classes:
1105 child = parent.modules.get(field)
1106 if child:
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001107 parent = module = child
Larry Hastings31826802013-10-19 00:09:25 -07001108 continue
1109 in_classes = True
1110 if not hasattr(parent, 'classes'):
1111 return module, cls
1112 child = parent.classes.get(field)
1113 if not child:
1114 fail('Parent class or module ' + '.'.join(so_far) + " does not exist.")
1115 cls = parent = child
1116
1117 return module, cls
1118
1119
1120def parse_file(filename, *, verify=True, output=None, encoding='utf-8'):
1121 extension = os.path.splitext(filename)[1][1:]
1122 if not extension:
1123 fail("Can't extract file type for file " + repr(filename))
1124
1125 try:
1126 language = extensions[extension]()
1127 except KeyError:
1128 fail("Can't identify file type for file " + repr(filename))
1129
1130 clinic = Clinic(language, verify=verify, filename=filename)
1131
1132 with open(filename, 'r', encoding=encoding) as f:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001133 raw = f.read()
1134
1135 cooked = clinic.parse(raw)
1136 if cooked == raw:
1137 return
Larry Hastings31826802013-10-19 00:09:25 -07001138
1139 directory = os.path.dirname(filename) or '.'
1140
1141 with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
Larry Hastingsdcd340e2013-11-23 14:58:45 -08001142 bytes = cooked.encode(encoding)
Larry Hastings31826802013-10-19 00:09:25 -07001143 tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
1144 with open(tmpfilename, "wb") as f:
1145 f.write(bytes)
1146 os.replace(tmpfilename, output or filename)
1147
1148
1149def compute_checksum(input):
1150 input = input or ''
1151 return hashlib.sha1(input.encode('utf-8')).hexdigest()
1152
1153
1154
1155
1156class PythonParser:
1157 def __init__(self, clinic):
1158 pass
1159
1160 def parse(self, block):
1161 s = io.StringIO()
1162 with OverrideStdioWith(s):
1163 exec(block.input)
1164 block.output = s.getvalue()
1165
1166
1167class Module:
1168 def __init__(self, name, module=None):
1169 self.name = name
1170 self.module = self.parent = module
1171
1172 self.modules = collections.OrderedDict()
1173 self.classes = collections.OrderedDict()
1174 self.functions = []
1175
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001176 def __repr__(self):
1177 return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
1178
Larry Hastings31826802013-10-19 00:09:25 -07001179class Class:
1180 def __init__(self, name, module=None, cls=None):
1181 self.name = name
1182 self.module = module
1183 self.cls = cls
1184 self.parent = cls or module
1185
1186 self.classes = collections.OrderedDict()
1187 self.functions = []
1188
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001189 def __repr__(self):
1190 return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
1191
Larry Hastings8666e652014-01-12 14:12:59 -08001192unsupported_special_methods = set("""
Larry Hastingsed4a1c52013-11-18 09:32:13 -08001193
Larry Hastings8666e652014-01-12 14:12:59 -08001194__abs__
1195__add__
1196__and__
1197__bytes__
1198__call__
1199__complex__
1200__delitem__
1201__divmod__
1202__eq__
1203__float__
1204__floordiv__
1205__ge__
1206__getattr__
1207__getattribute__
1208__getitem__
1209__gt__
1210__hash__
1211__iadd__
1212__iand__
1213__idivmod__
1214__ifloordiv__
1215__ilshift__
1216__imod__
1217__imul__
1218__index__
1219__int__
1220__invert__
1221__ior__
1222__ipow__
1223__irshift__
1224__isub__
1225__iter__
1226__itruediv__
1227__ixor__
1228__le__
1229__len__
1230__lshift__
1231__lt__
1232__mod__
1233__mul__
1234__neg__
1235__new__
1236__next__
1237__or__
1238__pos__
1239__pow__
1240__radd__
1241__rand__
1242__rdivmod__
1243__repr__
1244__rfloordiv__
1245__rlshift__
1246__rmod__
1247__rmul__
1248__ror__
1249__round__
1250__rpow__
1251__rrshift__
1252__rshift__
1253__rsub__
1254__rtruediv__
1255__rxor__
1256__setattr__
1257__setitem__
1258__str__
1259__sub__
1260__truediv__
1261__xor__
1262
1263""".strip().split())
1264
1265
1266INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6)
Larry Hastings31826802013-10-19 00:09:25 -07001267
1268class Function:
1269 """
1270 Mutable duck type for inspect.Function.
1271
1272 docstring - a str containing
1273 * embedded line breaks
1274 * text outdented to the left margin
1275 * no trailing whitespace.
1276 It will always be true that
1277 (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
1278 """
1279
1280 def __init__(self, parameters=None, *, name,
1281 module, cls=None, c_basename=None,
1282 full_name=None,
1283 return_converter, return_annotation=_empty,
1284 docstring=None, kind=CALLABLE, coexist=False):
1285 self.parameters = parameters or collections.OrderedDict()
1286 self.return_annotation = return_annotation
1287 self.name = name
1288 self.full_name = full_name
1289 self.module = module
1290 self.cls = cls
1291 self.parent = cls or module
1292 self.c_basename = c_basename
1293 self.return_converter = return_converter
1294 self.docstring = docstring or ''
1295 self.kind = kind
1296 self.coexist = coexist
Larry Hastingsebdcb502013-11-23 14:54:00 -08001297 self.self_converter = None
1298
1299 @property
1300 def methoddef_flags(self):
Larry Hastings8666e652014-01-12 14:12:59 -08001301 if self.kind in (METHOD_INIT, METHOD_NEW):
1302 return None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001303 flags = []
1304 if self.kind == CLASS_METHOD:
1305 flags.append('METH_CLASS')
1306 elif self.kind == STATIC_METHOD:
1307 flags.append('METH_STATIC')
1308 else:
1309 assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind)
1310 if self.coexist:
1311 flags.append('METH_COEXIST')
1312 return '|'.join(flags)
Larry Hastings31826802013-10-19 00:09:25 -07001313
1314 def __repr__(self):
1315 return '<clinic.Function ' + self.name + '>'
1316
1317
1318class Parameter:
1319 """
1320 Mutable duck type of inspect.Parameter.
1321 """
1322
1323 def __init__(self, name, kind, *, default=_empty,
1324 function, converter, annotation=_empty,
1325 docstring=None, group=0):
1326 self.name = name
1327 self.kind = kind
1328 self.default = default
1329 self.function = function
1330 self.converter = converter
1331 self.annotation = annotation
1332 self.docstring = docstring or ''
1333 self.group = group
1334
1335 def __repr__(self):
1336 return '<clinic.Parameter ' + self.name + '>'
1337
1338 def is_keyword_only(self):
1339 return self.kind == inspect.Parameter.KEYWORD_ONLY
1340
1341py_special_values = {
1342 NULL: "None",
1343}
1344
1345def py_repr(o):
1346 special = py_special_values.get(o)
1347 if special:
1348 return special
1349 return repr(o)
1350
1351
1352c_special_values = {
1353 NULL: "NULL",
1354 None: "Py_None",
1355}
1356
1357def c_repr(o):
1358 special = c_special_values.get(o)
1359 if special:
1360 return special
1361 if isinstance(o, str):
1362 return '"' + quoted_for_c_string(o) + '"'
1363 return repr(o)
1364
1365def add_c_converter(f, name=None):
1366 if not name:
1367 name = f.__name__
1368 if not name.endswith('_converter'):
1369 return f
1370 name = name[:-len('_converter')]
1371 converters[name] = f
1372 return f
1373
1374def add_default_legacy_c_converter(cls):
1375 # automatically add converter for default format unit
1376 # (but without stomping on the existing one if it's already
1377 # set, in case you subclass)
1378 if ((cls.format_unit != 'O&') and
1379 (cls.format_unit not in legacy_converters)):
1380 legacy_converters[cls.format_unit] = cls
1381 return cls
1382
1383def add_legacy_c_converter(format_unit, **kwargs):
1384 """
1385 Adds a legacy converter.
1386 """
1387 def closure(f):
1388 if not kwargs:
1389 added_f = f
1390 else:
1391 added_f = functools.partial(f, **kwargs)
1392 legacy_converters[format_unit] = added_f
1393 return f
1394 return closure
1395
1396class CConverterAutoRegister(type):
1397 def __init__(cls, name, bases, classdict):
1398 add_c_converter(cls)
1399 add_default_legacy_c_converter(cls)
1400
1401class CConverter(metaclass=CConverterAutoRegister):
1402 """
1403 For the init function, self, name, function, and default
1404 must be keyword-or-positional parameters. All other
1405 parameters (including "required" and "doc_default")
1406 must be keyword-only.
1407 """
1408
Larry Hastings78cf85c2014-01-04 12:44:57 -08001409 # The C type to use for this variable.
1410 # 'type' should be a Python string specifying the type, e.g. "int".
1411 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001412 type = None
Larry Hastings31826802013-10-19 00:09:25 -07001413
1414 # The Python default value for this parameter, as a Python value.
Larry Hastings78cf85c2014-01-04 12:44:57 -08001415 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001416 default = unspecified
1417
Larry Hastings4a55fc52014-01-12 11:09:57 -08001418 # If not None, default must be isinstance() of this type.
1419 # (You can also specify a tuple of types.)
1420 default_type = None
1421
Larry Hastings31826802013-10-19 00:09:25 -07001422 # "default" as it should appear in the documentation, as a string.
1423 # Or None if there is no default.
1424 doc_default = None
1425
Larry Hastingsabc716b2013-11-20 09:13:52 -08001426 # "default" converted into a str for rendering into Python code.
1427 py_default = None
1428
Larry Hastings31826802013-10-19 00:09:25 -07001429 # "default" converted into a C value, as a string.
1430 # Or None if there is no default.
1431 c_default = None
1432
Larry Hastingsabc716b2013-11-20 09:13:52 -08001433 # The default value used to initialize the C variable when
1434 # there is no default, but not specifying a default may
1435 # result in an "uninitialized variable" warning. This can
1436 # easily happen when using option groups--although
1437 # properly-written code won't actually use the variable,
1438 # the variable does get passed in to the _impl. (Ah, if
1439 # only dataflow analysis could inline the static function!)
1440 #
1441 # This value is specified as a string.
1442 # Every non-abstract subclass should supply a valid value.
1443 c_ignored_default = 'NULL'
1444
Larry Hastings31826802013-10-19 00:09:25 -07001445 # The C converter *function* to be used, if any.
1446 # (If this is not None, format_unit must be 'O&'.)
1447 converter = None
Larry Hastingsebdcb502013-11-23 14:54:00 -08001448
Larry Hastings78cf85c2014-01-04 12:44:57 -08001449 # Should Argument Clinic add a '&' before the name of
1450 # the variable when passing it into the _impl function?
Larry Hastings31826802013-10-19 00:09:25 -07001451 impl_by_reference = False
Larry Hastings78cf85c2014-01-04 12:44:57 -08001452
1453 # Should Argument Clinic add a '&' before the name of
1454 # the variable when passing it into PyArg_ParseTuple (AndKeywords)?
Larry Hastings31826802013-10-19 00:09:25 -07001455 parse_by_reference = True
Larry Hastings78cf85c2014-01-04 12:44:57 -08001456
1457 #############################################################
1458 #############################################################
1459 ## You shouldn't need to read anything below this point to ##
1460 ## write your own converter functions. ##
1461 #############################################################
1462 #############################################################
1463
1464 # The "format unit" to specify for this variable when
1465 # parsing arguments using PyArg_ParseTuple (AndKeywords).
1466 # Custom converters should always use the default value of 'O&'.
1467 format_unit = 'O&'
1468
1469 # What encoding do we want for this variable? Only used
1470 # by format units starting with 'e'.
1471 encoding = None
1472
Larry Hastings77561cc2014-01-07 12:13:13 -08001473 # Should this object be required to be a subclass of a specific type?
1474 # If not None, should be a string representing a pointer to a
1475 # PyTypeObject (e.g. "&PyUnicode_Type").
1476 # Only used by the 'O!' format unit (and the "object" converter).
1477 subclass_of = None
1478
Larry Hastings78cf85c2014-01-04 12:44:57 -08001479 # Do we want an adjacent '_length' variable for this variable?
1480 # Only used by format units ending with '#'.
Larry Hastings31826802013-10-19 00:09:25 -07001481 length = False
1482
Larry Hastings16c51912014-01-07 11:53:01 -08001483 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 -07001484 self.function = function
1485 self.name = name
1486
1487 if default is not unspecified:
Larry Hastings4a55fc52014-01-12 11:09:57 -08001488 if self.default_type and not isinstance(default, self.default_type):
1489 if isinstance(self.default_type, type):
1490 types_str = self.default_type.__name__
1491 else:
1492 types_str = ', '.join((cls.__name__ for cls in self.default_type))
1493 fail("{}: default value {!r} for field {} is not of type {}".format(
1494 self.__class__.__name__, default, name, types_str))
Larry Hastings31826802013-10-19 00:09:25 -07001495 self.default = default
Larry Hastings16c51912014-01-07 11:53:01 -08001496 self.py_default = py_default if py_default is not None else py_repr(default)
Larry Hastings31826802013-10-19 00:09:25 -07001497 self.doc_default = doc_default if doc_default is not None else self.py_default
Larry Hastings16c51912014-01-07 11:53:01 -08001498 self.c_default = c_default if c_default is not None else c_repr(default)
Larry Hastings4a55fc52014-01-12 11:09:57 -08001499 else:
1500 self.py_default = py_default
1501 self.doc_default = doc_default
1502 self.c_default = c_default
Larry Hastings31826802013-10-19 00:09:25 -07001503 if annotation != unspecified:
1504 fail("The 'annotation' parameter is not currently permitted.")
1505 self.required = required
1506 self.converter_init(**kwargs)
1507
1508 def converter_init(self):
1509 pass
1510
1511 def is_optional(self):
1512 return (self.default is not unspecified) and (not self.required)
1513
1514 def render(self, parameter, data):
1515 """
1516 parameter is a clinic.Parameter instance.
1517 data is a CRenderData instance.
1518 """
Larry Hastingsabc716b2013-11-20 09:13:52 -08001519 self.parameter = parameter
Larry Hastings90261132014-01-07 12:21:08 -08001520 original_name = self.name
1521 name = ensure_legal_c_identifier(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001522
1523 # declarations
1524 d = self.declaration()
1525 data.declarations.append(d)
1526
1527 # initializers
1528 initializers = self.initialize()
1529 if initializers:
1530 data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
1531
1532 # impl_arguments
1533 s = ("&" if self.impl_by_reference else "") + name
1534 data.impl_arguments.append(s)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001535 if self.length:
1536 data.impl_arguments.append(self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001537
1538 # keywords
Larry Hastings90261132014-01-07 12:21:08 -08001539 data.keywords.append(original_name)
Larry Hastings31826802013-10-19 00:09:25 -07001540
1541 # format_units
1542 if self.is_optional() and '|' not in data.format_units:
1543 data.format_units.append('|')
1544 if parameter.is_keyword_only() and '$' not in data.format_units:
1545 data.format_units.append('$')
1546 data.format_units.append(self.format_unit)
1547
1548 # parse_arguments
1549 self.parse_argument(data.parse_arguments)
1550
1551 # impl_parameters
1552 data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference))
Larry Hastingsebdcb502013-11-23 14:54:00 -08001553 if self.length:
1554 data.impl_parameters.append("Py_ssize_clean_t " + self.length_name())
Larry Hastings31826802013-10-19 00:09:25 -07001555
1556 # cleanup
1557 cleanup = self.cleanup()
1558 if cleanup:
1559 data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
1560
Larry Hastingsebdcb502013-11-23 14:54:00 -08001561 def length_name(self):
1562 """Computes the name of the associated "length" variable."""
1563 if not self.length:
1564 return None
1565 return ensure_legal_c_identifier(self.name) + "_length"
1566
Larry Hastings31826802013-10-19 00:09:25 -07001567 # Why is this one broken out separately?
1568 # For "positional-only" function parsing,
1569 # which generates a bunch of PyArg_ParseTuple calls.
1570 def parse_argument(self, list):
1571 assert not (self.converter and self.encoding)
1572 if self.format_unit == 'O&':
1573 assert self.converter
1574 list.append(self.converter)
1575
1576 if self.encoding:
Larry Hastings77561cc2014-01-07 12:13:13 -08001577 list.append(c_repr(self.encoding))
1578 elif self.subclass_of:
1579 list.append(self.subclass_of)
Larry Hastings31826802013-10-19 00:09:25 -07001580
Larry Hastingsebdcb502013-11-23 14:54:00 -08001581 legal_name = ensure_legal_c_identifier(self.name)
1582 s = ("&" if self.parse_by_reference else "") + legal_name
Larry Hastings31826802013-10-19 00:09:25 -07001583 list.append(s)
1584
Larry Hastingsebdcb502013-11-23 14:54:00 -08001585 if self.length:
1586 list.append("&" + self.length_name())
1587
Larry Hastings31826802013-10-19 00:09:25 -07001588 #
1589 # All the functions after here are intended as extension points.
1590 #
1591
1592 def simple_declaration(self, by_reference=False):
1593 """
1594 Computes the basic declaration of the variable.
1595 Used in computing the prototype declaration and the
1596 variable declaration.
1597 """
1598 prototype = [self.type]
1599 if by_reference or not self.type.endswith('*'):
1600 prototype.append(" ")
1601 if by_reference:
1602 prototype.append('*')
Larry Hastingsdfcd4672013-10-27 02:49:39 -07001603 prototype.append(ensure_legal_c_identifier(self.name))
Larry Hastings31826802013-10-19 00:09:25 -07001604 return "".join(prototype)
1605
1606 def declaration(self):
1607 """
1608 The C statement to declare this variable.
1609 """
1610 declaration = [self.simple_declaration()]
Larry Hastingsabc716b2013-11-20 09:13:52 -08001611 default = self.c_default
1612 if not default and self.parameter.group:
1613 default = self.c_ignored_default
1614 if default:
Larry Hastings31826802013-10-19 00:09:25 -07001615 declaration.append(" = ")
Larry Hastingsabc716b2013-11-20 09:13:52 -08001616 declaration.append(default)
Larry Hastings31826802013-10-19 00:09:25 -07001617 declaration.append(";")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001618 if self.length:
1619 declaration.append('\nPy_ssize_clean_t ')
1620 declaration.append(self.length_name())
1621 declaration.append(';')
Larry Hastings3f144c22014-01-06 10:34:00 -08001622 s = "".join(declaration)
1623 # double up curly-braces, this string will be used
1624 # as part of a format_map() template later
1625 s = s.replace("{", "{{")
1626 s = s.replace("}", "}}")
1627 return s
Larry Hastings31826802013-10-19 00:09:25 -07001628
1629 def initialize(self):
1630 """
1631 The C statements required to set up this variable before parsing.
1632 Returns a string containing this code indented at column 0.
1633 If no initialization is necessary, returns an empty string.
1634 """
1635 return ""
1636
1637 def cleanup(self):
1638 """
1639 The C statements required to clean up after this variable.
1640 Returns a string containing this code indented at column 0.
1641 If no cleanup is necessary, returns an empty string.
1642 """
1643 return ""
1644
1645
1646class bool_converter(CConverter):
1647 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001648 default_type = bool
Larry Hastings31826802013-10-19 00:09:25 -07001649 format_unit = 'p'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001650 c_ignored_default = '0'
Larry Hastings31826802013-10-19 00:09:25 -07001651
1652 def converter_init(self):
1653 self.default = bool(self.default)
1654 self.c_default = str(int(self.default))
1655
1656class char_converter(CConverter):
1657 type = 'char'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001658 default_type = str
Larry Hastings31826802013-10-19 00:09:25 -07001659 format_unit = 'c'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001660 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001661
Larry Hastings4a55fc52014-01-12 11:09:57 -08001662 def converter_init(self):
1663 if len(self.default) != 1:
1664 fail("char_converter: illegal default value " + repr(self.default))
1665
1666
Larry Hastings31826802013-10-19 00:09:25 -07001667@add_legacy_c_converter('B', bitwise=True)
1668class byte_converter(CConverter):
1669 type = 'byte'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001670 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001671 format_unit = 'b'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001672 c_ignored_default = "'\0'"
Larry Hastings31826802013-10-19 00:09:25 -07001673
1674 def converter_init(self, *, bitwise=False):
1675 if bitwise:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001676 self.format_unit = 'B'
Larry Hastings31826802013-10-19 00:09:25 -07001677
1678class short_converter(CConverter):
1679 type = 'short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001680 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001681 format_unit = 'h'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001682 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001683
1684class unsigned_short_converter(CConverter):
1685 type = 'unsigned short'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001686 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001687 format_unit = 'H'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001688 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001689
1690 def converter_init(self, *, bitwise=False):
1691 if not bitwise:
1692 fail("Unsigned shorts must be bitwise (for now).")
1693
Larry Hastingsebdcb502013-11-23 14:54:00 -08001694@add_legacy_c_converter('C', types='str')
Larry Hastings31826802013-10-19 00:09:25 -07001695class int_converter(CConverter):
1696 type = 'int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001697 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001698 format_unit = 'i'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001699 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001700
Larry Hastingsebdcb502013-11-23 14:54:00 -08001701 def converter_init(self, *, types='int'):
1702 if types == 'str':
1703 self.format_unit = 'C'
1704 elif types != 'int':
1705 fail("int_converter: illegal 'types' argument")
Larry Hastings31826802013-10-19 00:09:25 -07001706
1707class unsigned_int_converter(CConverter):
1708 type = 'unsigned int'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001709 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001710 format_unit = 'I'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001711 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001712
1713 def converter_init(self, *, bitwise=False):
1714 if not bitwise:
1715 fail("Unsigned ints must be bitwise (for now).")
1716
1717class long_converter(CConverter):
1718 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001719 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001720 format_unit = 'l'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001721 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001722
1723class unsigned_long_converter(CConverter):
1724 type = 'unsigned long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001725 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001726 format_unit = 'k'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001727 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001728
1729 def converter_init(self, *, bitwise=False):
1730 if not bitwise:
1731 fail("Unsigned longs must be bitwise (for now).")
1732
1733class PY_LONG_LONG_converter(CConverter):
1734 type = 'PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001735 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001736 format_unit = 'L'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001737 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001738
1739class unsigned_PY_LONG_LONG_converter(CConverter):
1740 type = 'unsigned PY_LONG_LONG'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001741 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001742 format_unit = 'K'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001743 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001744
1745 def converter_init(self, *, bitwise=False):
1746 if not bitwise:
1747 fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
1748
1749class Py_ssize_t_converter(CConverter):
1750 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001751 default_type = int
Larry Hastings31826802013-10-19 00:09:25 -07001752 format_unit = 'n'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001753 c_ignored_default = "0"
Larry Hastings31826802013-10-19 00:09:25 -07001754
1755
1756class float_converter(CConverter):
1757 type = 'float'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001758 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07001759 format_unit = 'f'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001760 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001761
1762class double_converter(CConverter):
1763 type = 'double'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001764 default_type = float
Larry Hastings31826802013-10-19 00:09:25 -07001765 format_unit = 'd'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001766 c_ignored_default = "0.0"
Larry Hastings31826802013-10-19 00:09:25 -07001767
1768
1769class Py_complex_converter(CConverter):
1770 type = 'Py_complex'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001771 default_type = complex
Larry Hastings31826802013-10-19 00:09:25 -07001772 format_unit = 'D'
Larry Hastingsabc716b2013-11-20 09:13:52 -08001773 c_ignored_default = "{0.0, 0.0}"
Larry Hastings31826802013-10-19 00:09:25 -07001774
1775
1776class object_converter(CConverter):
1777 type = 'PyObject *'
1778 format_unit = 'O'
1779
Larry Hastings4a55fc52014-01-12 11:09:57 -08001780 def converter_init(self, *, converter=None, type=None, subclass_of=None):
1781 if converter:
1782 if subclass_of:
1783 fail("object: Cannot pass in both 'converter' and 'subclass_of'")
1784 self.format_unit = 'O&'
1785 self.converter = converter
1786 elif subclass_of:
Larry Hastings31826802013-10-19 00:09:25 -07001787 self.format_unit = 'O!'
Larry Hastings77561cc2014-01-07 12:13:13 -08001788 self.subclass_of = subclass_of
Larry Hastings4a55fc52014-01-12 11:09:57 -08001789
Larry Hastings77561cc2014-01-07 12:13:13 -08001790 if type is not None:
1791 self.type = type
Larry Hastings31826802013-10-19 00:09:25 -07001792
1793
Larry Hastingsebdcb502013-11-23 14:54:00 -08001794@add_legacy_c_converter('s#', length=True)
1795@add_legacy_c_converter('y', type="bytes")
1796@add_legacy_c_converter('y#', type="bytes", length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001797@add_legacy_c_converter('z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001798@add_legacy_c_converter('z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001799class str_converter(CConverter):
1800 type = 'const char *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001801 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001802 format_unit = 's'
1803
Larry Hastingsebdcb502013-11-23 14:54:00 -08001804 def converter_init(self, *, encoding=None, types="str",
1805 length=False, nullable=False, zeroes=False):
1806
1807 types = set(types.strip().split())
1808 bytes_type = set(("bytes",))
1809 str_type = set(("str",))
1810 all_3_type = set(("bytearray",)) | bytes_type | str_type
1811 is_bytes = types == bytes_type
1812 is_str = types == str_type
1813 is_all_3 = types == all_3_type
1814
1815 self.length = bool(length)
1816 format_unit = None
1817
1818 if encoding:
1819 self.encoding = encoding
1820
1821 if is_str and not (length or zeroes or nullable):
1822 format_unit = 'es'
1823 elif is_all_3 and not (length or zeroes or nullable):
1824 format_unit = 'et'
1825 elif is_str and length and zeroes and not nullable:
1826 format_unit = 'es#'
1827 elif is_all_3 and length and not (nullable or zeroes):
1828 format_unit = 'et#'
1829
1830 if format_unit.endswith('#'):
Larry Hastings2f9a9aa2013-11-24 04:23:35 -08001831 print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.")
Larry Hastingsebdcb502013-11-23 14:54:00 -08001832 # TODO set pointer to NULL
1833 # TODO add cleanup for buffer
1834 pass
1835
1836 else:
1837 if zeroes:
1838 fail("str_converter: illegal combination of arguments (zeroes is only legal with an encoding)")
1839
1840 if is_bytes and not (nullable or length):
1841 format_unit = 'y'
1842 elif is_bytes and length and not nullable:
1843 format_unit = 'y#'
1844 elif is_str and not (nullable or length):
1845 format_unit = 's'
1846 elif is_str and length and not nullable:
1847 format_unit = 's#'
1848 elif is_str and nullable and not length:
1849 format_unit = 'z'
1850 elif is_str and nullable and length:
1851 format_unit = 'z#'
1852
1853 if not format_unit:
1854 fail("str_converter: illegal combination of arguments")
1855 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001856
1857
1858class PyBytesObject_converter(CConverter):
1859 type = 'PyBytesObject *'
1860 format_unit = 'S'
1861
1862class PyByteArrayObject_converter(CConverter):
1863 type = 'PyByteArrayObject *'
1864 format_unit = 'Y'
1865
1866class unicode_converter(CConverter):
1867 type = 'PyObject *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001868 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001869 format_unit = 'U'
1870
Larry Hastingsebdcb502013-11-23 14:54:00 -08001871@add_legacy_c_converter('u#', length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001872@add_legacy_c_converter('Z', nullable=True)
Larry Hastingsebdcb502013-11-23 14:54:00 -08001873@add_legacy_c_converter('Z#', nullable=True, length=True)
Larry Hastings31826802013-10-19 00:09:25 -07001874class Py_UNICODE_converter(CConverter):
1875 type = 'Py_UNICODE *'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001876 default_type = (str, Null, NoneType)
Larry Hastings31826802013-10-19 00:09:25 -07001877 format_unit = 'u'
1878
Larry Hastingsebdcb502013-11-23 14:54:00 -08001879 def converter_init(self, *, nullable=False, length=False):
1880 format_unit = 'Z' if nullable else 'u'
1881 if length:
1882 format_unit += '#'
1883 self.length = True
1884 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001885
Larry Hastingsebdcb502013-11-23 14:54:00 -08001886#
1887# We define three string conventions for buffer types in the 'types' argument:
1888# 'buffer' : any object supporting the buffer interface
1889# 'rwbuffer': any object supporting the buffer interface, but must be writeable
1890# 'robuffer': any object supporting the buffer interface, but must not be writeable
1891#
1892@add_legacy_c_converter('s*', types='str bytes bytearray buffer')
1893@add_legacy_c_converter('z*', types='str bytes bytearray buffer', nullable=True)
1894@add_legacy_c_converter('w*', types='bytearray rwbuffer')
Larry Hastings31826802013-10-19 00:09:25 -07001895class Py_buffer_converter(CConverter):
1896 type = 'Py_buffer'
1897 format_unit = 'y*'
1898 impl_by_reference = True
Larry Hastings4a55fc52014-01-12 11:09:57 -08001899 c_ignored_default = "{NULL, NULL}"
Larry Hastings31826802013-10-19 00:09:25 -07001900
Larry Hastingsebdcb502013-11-23 14:54:00 -08001901 def converter_init(self, *, types='bytes bytearray buffer', nullable=False):
Larry Hastings4a55fc52014-01-12 11:09:57 -08001902 if self.default not in (unspecified, None):
1903 fail("The only legal default value for Py_buffer is None.")
Larry Hastings3f144c22014-01-06 10:34:00 -08001904 self.c_default = self.c_ignored_default
Larry Hastingsebdcb502013-11-23 14:54:00 -08001905 types = set(types.strip().split())
1906 bytes_type = set(('bytes',))
1907 bytearray_type = set(('bytearray',))
1908 buffer_type = set(('buffer',))
1909 rwbuffer_type = set(('rwbuffer',))
1910 robuffer_type = set(('robuffer',))
1911 str_type = set(('str',))
1912 bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type
1913
1914 format_unit = None
1915 if types == (str_type | bytes_bytearray_buffer_type):
1916 format_unit = 's*' if not nullable else 'z*'
Larry Hastings31826802013-10-19 00:09:25 -07001917 else:
Larry Hastingsebdcb502013-11-23 14:54:00 -08001918 if nullable:
1919 fail('Py_buffer_converter: illegal combination of arguments (nullable=True)')
1920 elif types == (bytes_bytearray_buffer_type):
1921 format_unit = 'y*'
Larry Hastings4a55fc52014-01-12 11:09:57 -08001922 elif types == (bytearray_type | rwbuffer_type):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001923 format_unit = 'w*'
1924 if not format_unit:
1925 fail("Py_buffer_converter: illegal combination of arguments")
1926
1927 self.format_unit = format_unit
Larry Hastings31826802013-10-19 00:09:25 -07001928
1929 def cleanup(self):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001930 name = ensure_legal_c_identifier(self.name)
Larry Hastings4a55fc52014-01-12 11:09:57 -08001931 return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
Larry Hastingsebdcb502013-11-23 14:54:00 -08001932
1933
1934class self_converter(CConverter):
1935 """
1936 A special-case converter:
1937 this is the default converter used for "self".
1938 """
1939 type = "PyObject *"
Larry Hastings78cf85c2014-01-04 12:44:57 -08001940 def converter_init(self, *, type=None):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001941 f = self.function
Larry Hastings8666e652014-01-12 14:12:59 -08001942 if f.kind in (CALLABLE, METHOD_INIT):
Larry Hastingsebdcb502013-11-23 14:54:00 -08001943 if f.cls:
1944 self.name = "self"
1945 else:
1946 self.name = "module"
1947 self.type = "PyModuleDef *"
1948 elif f.kind == STATIC_METHOD:
1949 self.name = "null"
1950 self.type = "void *"
1951 elif f.kind == CLASS_METHOD:
1952 self.name = "cls"
1953 self.type = "PyTypeObject *"
Larry Hastings8666e652014-01-12 14:12:59 -08001954 elif f.kind == METHOD_NEW:
1955 self.name = "type"
1956 self.type = "PyTypeObject *"
Larry Hastingsebdcb502013-11-23 14:54:00 -08001957
Larry Hastings78cf85c2014-01-04 12:44:57 -08001958 if type:
1959 self.type = type
1960
Larry Hastingsebdcb502013-11-23 14:54:00 -08001961 def render(self, parameter, data):
1962 fail("render() should never be called on self_converter instances")
1963
Larry Hastings31826802013-10-19 00:09:25 -07001964
1965
1966def add_c_return_converter(f, name=None):
1967 if not name:
1968 name = f.__name__
1969 if not name.endswith('_return_converter'):
1970 return f
1971 name = name[:-len('_return_converter')]
1972 return_converters[name] = f
1973 return f
1974
1975
1976class CReturnConverterAutoRegister(type):
1977 def __init__(cls, name, bases, classdict):
1978 add_c_return_converter(cls)
1979
1980class CReturnConverter(metaclass=CReturnConverterAutoRegister):
1981
Larry Hastings78cf85c2014-01-04 12:44:57 -08001982 # The C type to use for this variable.
1983 # 'type' should be a Python string specifying the type, e.g. "int".
1984 # If this is a pointer type, the type string should end with ' *'.
Larry Hastings31826802013-10-19 00:09:25 -07001985 type = 'PyObject *'
Larry Hastings78cf85c2014-01-04 12:44:57 -08001986
1987 # The Python default value for this parameter, as a Python value.
1988 # Or the magic value "unspecified" if there is no default.
Larry Hastings31826802013-10-19 00:09:25 -07001989 default = None
1990
1991 def __init__(self, *, doc_default=None, **kwargs):
1992 self.doc_default = doc_default
1993 try:
1994 self.return_converter_init(**kwargs)
1995 except TypeError as e:
1996 s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
1997 sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
1998
1999 def return_converter_init(self):
2000 pass
2001
2002 def declare(self, data, name="_return_value"):
2003 line = []
2004 add = line.append
2005 add(self.type)
2006 if not self.type.endswith('*'):
2007 add(' ')
2008 add(name + ';')
2009 data.declarations.append(''.join(line))
2010 data.return_value = name
2011
2012 def err_occurred_if(self, expr, data):
2013 data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
2014
2015 def err_occurred_if_null_pointer(self, variable, data):
2016 data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
2017
2018 def render(self, function, data):
2019 """
2020 function is a clinic.Function instance.
2021 data is a CRenderData instance.
2022 """
2023 pass
2024
2025add_c_return_converter(CReturnConverter, 'object')
2026
Larry Hastings78cf85c2014-01-04 12:44:57 -08002027class NoneType_return_converter(CReturnConverter):
2028 def render(self, function, data):
2029 self.declare(data)
2030 data.return_conversion.append('''
2031if (_return_value != Py_None)
2032 goto exit;
2033return_value = Py_None;
2034Py_INCREF(Py_None);
2035'''.strip())
2036
Larry Hastings4a55fc52014-01-12 11:09:57 -08002037class bool_return_converter(CReturnConverter):
Larry Hastings31826802013-10-19 00:09:25 -07002038 type = 'int'
2039
2040 def render(self, function, data):
2041 self.declare(data)
2042 self.err_occurred_if("_return_value == -1", data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002043 data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
Larry Hastings31826802013-10-19 00:09:25 -07002044
2045class long_return_converter(CReturnConverter):
2046 type = 'long'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002047 conversion_fn = 'PyLong_FromLong'
2048 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002049
2050 def render(self, function, data):
2051 self.declare(data)
2052 self.err_occurred_if("_return_value == -1", data)
2053 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002054 ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
Larry Hastings31826802013-10-19 00:09:25 -07002055
Larry Hastings4a55fc52014-01-12 11:09:57 -08002056class int_return_converter(long_return_converter):
2057 type = 'int'
2058 cast = '(long)'
Larry Hastings31826802013-10-19 00:09:25 -07002059
Larry Hastings4a55fc52014-01-12 11:09:57 -08002060class unsigned_long_return_converter(long_return_converter):
2061 type = 'unsigned long'
2062 conversion_fn = 'PyLong_FromUnsignedLong'
2063
2064class unsigned_int_return_converter(unsigned_long_return_converter):
2065 type = 'unsigned int'
2066 cast = '(unsigned long)'
2067
2068class Py_ssize_t_return_converter(long_return_converter):
Larry Hastings31826802013-10-19 00:09:25 -07002069 type = 'Py_ssize_t'
Larry Hastings4a55fc52014-01-12 11:09:57 -08002070 conversion_fn = 'PyLong_FromSsize_t'
2071
2072class size_t_return_converter(long_return_converter):
2073 type = 'size_t'
2074 conversion_fn = 'PyLong_FromSize_t'
2075
2076
2077class double_return_converter(CReturnConverter):
2078 type = 'double'
2079 cast = ''
Larry Hastings31826802013-10-19 00:09:25 -07002080
2081 def render(self, function, data):
2082 self.declare(data)
Larry Hastings4a55fc52014-01-12 11:09:57 -08002083 self.err_occurred_if("_return_value == -1.0", data)
Larry Hastings31826802013-10-19 00:09:25 -07002084 data.return_conversion.append(
Larry Hastings4a55fc52014-01-12 11:09:57 -08002085 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
2086
2087class float_return_converter(double_return_converter):
2088 type = 'float'
2089 cast = '(double)'
Larry Hastings31826802013-10-19 00:09:25 -07002090
2091
2092class DecodeFSDefault_return_converter(CReturnConverter):
2093 type = 'char *'
2094
2095 def render(self, function, data):
2096 self.declare(data)
2097 self.err_occurred_if_null_pointer("_return_value", data)
2098 data.return_conversion.append(
2099 'return_value = PyUnicode_DecodeFSDefault(_return_value);\n')
2100
2101
2102class IndentStack:
2103 def __init__(self):
2104 self.indents = []
2105 self.margin = None
2106
2107 def _ensure(self):
2108 if not self.indents:
2109 fail('IndentStack expected indents, but none are defined.')
2110
2111 def measure(self, line):
2112 """
2113 Returns the length of the line's margin.
2114 """
2115 if '\t' in line:
2116 fail('Tab characters are illegal in the Clinic DSL.')
2117 stripped = line.lstrip()
2118 if not len(stripped):
2119 # we can't tell anything from an empty line
2120 # so just pretend it's indented like our current indent
2121 self._ensure()
2122 return self.indents[-1]
2123 return len(line) - len(stripped)
2124
2125 def infer(self, line):
2126 """
2127 Infer what is now the current margin based on this line.
2128 Returns:
2129 1 if we have indented (or this is the first margin)
2130 0 if the margin has not changed
2131 -N if we have dedented N times
2132 """
2133 indent = self.measure(line)
2134 margin = ' ' * indent
2135 if not self.indents:
2136 self.indents.append(indent)
2137 self.margin = margin
2138 return 1
2139 current = self.indents[-1]
2140 if indent == current:
2141 return 0
2142 if indent > current:
2143 self.indents.append(indent)
2144 self.margin = margin
2145 return 1
2146 # indent < current
2147 if indent not in self.indents:
2148 fail("Illegal outdent.")
2149 outdent_count = 0
2150 while indent != current:
2151 self.indents.pop()
2152 current = self.indents[-1]
2153 outdent_count -= 1
2154 self.margin = margin
2155 return outdent_count
2156
2157 @property
2158 def depth(self):
2159 """
2160 Returns how many margins are currently defined.
2161 """
2162 return len(self.indents)
2163
2164 def indent(self, line):
2165 """
2166 Indents a line by the currently defined margin.
2167 """
2168 return self.margin + line
2169
2170 def dedent(self, line):
2171 """
2172 Dedents a line by the currently defined margin.
2173 (The inverse of 'indent'.)
2174 """
2175 margin = self.margin
2176 indent = self.indents[-1]
2177 if not line.startswith(margin):
2178 fail('Cannot dedent, line does not start with the previous margin:')
2179 return line[indent:]
2180
2181
2182class DSLParser:
2183 def __init__(self, clinic):
2184 self.clinic = clinic
2185
2186 self.directives = {}
2187 for name in dir(self):
2188 # functions that start with directive_ are added to directives
2189 _, s, key = name.partition("directive_")
2190 if s:
2191 self.directives[key] = getattr(self, name)
2192
2193 # functions that start with at_ are too, with an @ in front
2194 _, s, key = name.partition("at_")
2195 if s:
2196 self.directives['@' + key] = getattr(self, name)
2197
2198 self.reset()
2199
2200 def reset(self):
2201 self.function = None
2202 self.state = self.state_dsl_start
2203 self.parameter_indent = None
2204 self.keyword_only = False
2205 self.group = 0
2206 self.parameter_state = self.ps_start
2207 self.indent = IndentStack()
2208 self.kind = CALLABLE
2209 self.coexist = False
2210
Larry Hastingsebdcb502013-11-23 14:54:00 -08002211 def directive_version(self, required):
2212 global version
2213 if version_comparitor(version, required) < 0:
2214 fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required)
2215
Larry Hastings31826802013-10-19 00:09:25 -07002216 def directive_module(self, name):
2217 fields = name.split('.')
2218 new = fields.pop()
2219 module, cls = self.clinic._module_and_class(fields)
2220 if cls:
2221 fail("Can't nest a module inside a class!")
2222 m = Module(name, module)
2223 module.modules[name] = m
2224 self.block.signatures.append(m)
2225
2226 def directive_class(self, name):
2227 fields = name.split('.')
2228 in_classes = False
2229 parent = self
2230 name = fields.pop()
2231 so_far = []
2232 module, cls = self.clinic._module_and_class(fields)
2233
Larry Hastings31826802013-10-19 00:09:25 -07002234 c = Class(name, module, cls)
Larry Hastings31826802013-10-19 00:09:25 -07002235 if cls:
2236 cls.classes[name] = c
Larry Hastingsed4a1c52013-11-18 09:32:13 -08002237 else:
2238 module.classes[name] = c
Larry Hastings31826802013-10-19 00:09:25 -07002239 self.block.signatures.append(c)
2240
2241 def at_classmethod(self):
2242 assert self.kind is CALLABLE
2243 self.kind = CLASS_METHOD
2244
2245 def at_staticmethod(self):
2246 assert self.kind is CALLABLE
2247 self.kind = STATIC_METHOD
2248
2249 def at_coexist(self):
2250 assert self.coexist == False
2251 self.coexist = True
2252
Larry Hastingsebdcb502013-11-23 14:54:00 -08002253
Larry Hastings31826802013-10-19 00:09:25 -07002254 def parse(self, block):
2255 self.reset()
2256 self.block = block
2257 block_start = self.clinic.block_parser.line_number
2258 lines = block.input.split('\n')
2259 for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
2260 if '\t' in line:
2261 fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
2262 self.state(line)
2263
2264 self.next(self.state_terminal)
2265 self.state(None)
2266
2267 block.output = self.clinic.language.render(block.signatures)
2268
2269 @staticmethod
2270 def ignore_line(line):
2271 # ignore comment-only lines
2272 if line.lstrip().startswith('#'):
2273 return True
2274
2275 # Ignore empty lines too
2276 # (but not in docstring sections!)
2277 if not line.strip():
2278 return True
2279
2280 return False
2281
2282 @staticmethod
2283 def calculate_indent(line):
2284 return len(line) - len(line.strip())
2285
2286 def next(self, state, line=None):
2287 # real_print(self.state.__name__, "->", state.__name__, ", line=", line)
2288 self.state = state
2289 if line is not None:
2290 self.state(line)
2291
2292 def state_dsl_start(self, line):
2293 # self.block = self.ClinicOutputBlock(self)
2294 if self.ignore_line(line):
2295 return
2296 self.next(self.state_modulename_name, line)
2297
2298 def state_modulename_name(self, line):
2299 # looking for declaration, which establishes the leftmost column
2300 # line should be
2301 # modulename.fnname [as c_basename] [-> return annotation]
2302 # square brackets denote optional syntax.
2303 #
Larry Hastings4a714d42014-01-14 22:22:41 -08002304 # alternatively:
2305 # modulename.fnname [as c_basename] = modulename.existing_fn_name
2306 # clones the parameters and return converter from that
2307 # function. you can't modify them. you must enter a
2308 # new docstring.
2309 #
Larry Hastings31826802013-10-19 00:09:25 -07002310 # (but we might find a directive first!)
2311 #
2312 # this line is permitted to start with whitespace.
2313 # we'll call this number of spaces F (for "function").
2314
2315 if not line.strip():
2316 return
2317
2318 self.indent.infer(line)
2319
2320 # is it a directive?
2321 fields = shlex.split(line)
2322 directive_name = fields[0]
2323 directive = self.directives.get(directive_name, None)
2324 if directive:
2325 directive(*fields[1:])
2326 return
2327
Larry Hastings4a714d42014-01-14 22:22:41 -08002328 # are we cloning?
2329 before, equals, existing = line.rpartition('=')
2330 if equals:
2331 full_name, _, c_basename = before.partition(' as ')
2332 full_name = full_name.strip()
2333 c_basename = c_basename.strip()
2334 existing = existing.strip()
2335 if (is_legal_py_identifier(full_name) and
2336 (not c_basename or is_legal_c_identifier(c_basename)) and
2337 is_legal_py_identifier(existing)):
2338 # we're cloning!
2339 fields = [x.strip() for x in existing.split('.')]
2340 function_name = fields.pop()
2341 module, cls = self.clinic._module_and_class(fields)
2342
2343 for existing_function in (cls or module).functions:
2344 if existing_function.name == function_name:
2345 break
2346 else:
2347 existing_function = None
2348 if not existing_function:
2349 fail("Couldn't find existing function " + repr(existing) + "!")
2350
2351 fields = [x.strip() for x in full_name.split('.')]
2352 function_name = fields.pop()
2353 module, cls = self.clinic._module_and_class(fields)
2354
2355 if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
2356 fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
2357 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2358 return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
2359
2360 self.function.parameters = existing_function.parameters.copy()
2361
2362 self.block.signatures.append(self.function)
2363 (cls or module).functions.append(self.function)
2364 self.next(self.state_function_docstring)
2365 return
2366
Larry Hastings31826802013-10-19 00:09:25 -07002367 line, _, returns = line.partition('->')
2368
2369 full_name, _, c_basename = line.partition(' as ')
2370 full_name = full_name.strip()
2371 c_basename = c_basename.strip() or None
2372
Larry Hastingsdfcd4672013-10-27 02:49:39 -07002373 if not is_legal_py_identifier(full_name):
2374 fail("Illegal function name: {}".format(full_name))
2375 if c_basename and not is_legal_c_identifier(c_basename):
2376 fail("Illegal C basename: {}".format(c_basename))
2377
Larry Hastings31826802013-10-19 00:09:25 -07002378 if not returns:
2379 return_converter = CReturnConverter()
2380 else:
2381 ast_input = "def x() -> {}: pass".format(returns)
2382 module = None
2383 try:
2384 module = ast.parse(ast_input)
2385 except SyntaxError:
2386 pass
2387 if not module:
2388 fail("Badly-formed annotation for " + full_name + ": " + returns)
2389 try:
2390 name, legacy, kwargs = self.parse_converter(module.body[0].returns)
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002391 if legacy:
2392 fail("Legacy converter {!r} not allowed as a return converter"
2393 .format(name))
Larry Hastings31826802013-10-19 00:09:25 -07002394 if name not in return_converters:
Antoine Pitroud7fb7912014-01-14 21:02:43 +01002395 fail("No available return converter called " + repr(name))
Larry Hastings31826802013-10-19 00:09:25 -07002396 return_converter = return_converters[name](**kwargs)
2397 except ValueError:
2398 fail("Badly-formed annotation for " + full_name + ": " + returns)
2399
2400 fields = [x.strip() for x in full_name.split('.')]
2401 function_name = fields.pop()
2402 module, cls = self.clinic._module_and_class(fields)
2403
Larry Hastings8666e652014-01-12 14:12:59 -08002404 fields = full_name.split('.')
2405 if fields[-1] == '__new__':
2406 if (self.kind != CLASS_METHOD) or (not cls):
2407 fail("__new__ must be a class method!")
2408 self.kind = METHOD_NEW
2409 elif fields[-1] == '__init__':
2410 if (self.kind != CALLABLE) or (not cls):
2411 fail("__init__ must be a normal method, not a class or static method!")
2412 self.kind = METHOD_INIT
2413 elif fields[-1] in unsupported_special_methods:
2414 fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
2415
Larry Hastings31826802013-10-19 00:09:25 -07002416 if not module:
2417 fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
2418 self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
2419 return_converter=return_converter, kind=self.kind, coexist=self.coexist)
2420 self.block.signatures.append(self.function)
Larry Hastings4a714d42014-01-14 22:22:41 -08002421 (cls or module).functions.append(self.function)
Larry Hastings31826802013-10-19 00:09:25 -07002422 self.next(self.state_parameters_start)
2423
2424 # Now entering the parameters section. The rules, formally stated:
2425 #
2426 # * All lines must be indented with spaces only.
2427 # * The first line must be a parameter declaration.
2428 # * The first line must be indented.
2429 # * This first line establishes the indent for parameters.
2430 # * We'll call this number of spaces P (for "parameter").
2431 # * Thenceforth:
2432 # * Lines indented with P spaces specify a parameter.
2433 # * Lines indented with > P spaces are docstrings for the previous
2434 # parameter.
2435 # * We'll call this number of spaces D (for "docstring").
2436 # * All subsequent lines indented with >= D spaces are stored as
2437 # part of the per-parameter docstring.
2438 # * All lines will have the first D spaces of the indent stripped
2439 # before they are stored.
2440 # * It's illegal to have a line starting with a number of spaces X
2441 # such that P < X < D.
2442 # * A line with < P spaces is the first line of the function
2443 # docstring, which ends processing for parameters and per-parameter
2444 # docstrings.
2445 # * The first line of the function docstring must be at the same
2446 # indent as the function declaration.
2447 # * It's illegal to have any line in the parameters section starting
2448 # with X spaces such that F < X < P. (As before, F is the indent
2449 # of the function declaration.)
2450 #
2451 ##############
2452 #
2453 # Also, currently Argument Clinic places the following restrictions on groups:
2454 # * Each group must contain at least one parameter.
2455 # * Each group may contain at most one group, which must be the furthest
2456 # thing in the group from the required parameters. (The nested group
2457 # must be the first in the group when it's before the required
2458 # parameters, and the last thing in the group when after the required
2459 # parameters.)
2460 # * There may be at most one (top-level) group to the left or right of
2461 # the required parameters.
2462 # * You must specify a slash, and it must be after all parameters.
2463 # (In other words: either all parameters are positional-only,
2464 # or none are.)
2465 #
2466 # Said another way:
2467 # * Each group must contain at least one parameter.
2468 # * All left square brackets before the required parameters must be
2469 # consecutive. (You can't have a left square bracket followed
2470 # by a parameter, then another left square bracket. You can't
2471 # have a left square bracket, a parameter, a right square bracket,
2472 # and then a left square bracket.)
2473 # * All right square brackets after the required parameters must be
2474 # consecutive.
2475 #
2476 # These rules are enforced with a single state variable:
2477 # "parameter_state". (Previously the code was a miasma of ifs and
2478 # separate boolean state variables.) The states are:
2479 #
2480 # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
2481 # 01 2 3 4 5 6 <- state transitions
2482 #
2483 # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
2484 # 1: ps_left_square_before. left square brackets before required parameters.
2485 # 2: ps_group_before. in a group, before required parameters.
2486 # 3: ps_required. required parameters. (renumber left groups!)
2487 # 4: ps_group_after. in a group, after required parameters.
2488 # 5: ps_right_square_after. right square brackets after required parameters.
2489 # 6: ps_seen_slash. seen slash.
2490 ps_start, ps_left_square_before, ps_group_before, ps_required, \
2491 ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
2492
2493 def state_parameters_start(self, line):
2494 if self.ignore_line(line):
2495 return
2496
2497 # if this line is not indented, we have no parameters
2498 if not self.indent.infer(line):
2499 return self.next(self.state_function_docstring, line)
2500
2501 return self.next(self.state_parameter, line)
2502
2503
2504 def to_required(self):
2505 """
2506 Transition to the "required" parameter state.
2507 """
2508 if self.parameter_state != self.ps_required:
2509 self.parameter_state = self.ps_required
2510 for p in self.function.parameters.values():
2511 p.group = -p.group
2512
2513 def state_parameter(self, line):
2514 if self.ignore_line(line):
2515 return
2516
2517 assert self.indent.depth == 2
2518 indent = self.indent.infer(line)
2519 if indent == -1:
2520 # we outdented, must be to definition column
2521 return self.next(self.state_function_docstring, line)
2522
2523 if indent == 1:
2524 # we indented, must be to new parameter docstring column
2525 return self.next(self.state_parameter_docstring_start, line)
2526
2527 line = line.lstrip()
2528
2529 if line in ('*', '/', '[', ']'):
2530 self.parse_special_symbol(line)
2531 return
2532
2533 if self.parameter_state in (self.ps_start, self.ps_required):
2534 self.to_required()
2535 elif self.parameter_state == self.ps_left_square_before:
2536 self.parameter_state = self.ps_group_before
2537 elif self.parameter_state == self.ps_group_before:
2538 if not self.group:
2539 self.to_required()
2540 elif self.parameter_state == self.ps_group_after:
2541 pass
2542 else:
2543 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2544
2545 ast_input = "def x({}): pass".format(line)
2546 module = None
2547 try:
2548 module = ast.parse(ast_input)
2549 except SyntaxError:
2550 pass
2551 if not module:
Larry Hastingsef3b1fb2013-10-22 23:26:23 -07002552 fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line)
Larry Hastings31826802013-10-19 00:09:25 -07002553
2554 function_args = module.body[0].args
2555 parameter = function_args.args[0]
2556
Larry Hastings16c51912014-01-07 11:53:01 -08002557 py_default = None
2558
2559 parameter_name = parameter.arg
2560 name, legacy, kwargs = self.parse_converter(parameter.annotation)
2561
Larry Hastings31826802013-10-19 00:09:25 -07002562 if function_args.defaults:
2563 expr = function_args.defaults[0]
2564 # mild hack: explicitly support NULL as a default value
2565 if isinstance(expr, ast.Name) and expr.id == 'NULL':
2566 value = NULL
Larry Hastings16c51912014-01-07 11:53:01 -08002567 elif isinstance(expr, ast.Attribute):
Larry Hastings4a55fc52014-01-12 11:09:57 -08002568 c_default = kwargs.get("c_default")
2569 if not (isinstance(c_default, str) and c_default):
2570 fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.")
2571
Larry Hastings16c51912014-01-07 11:53:01 -08002572 a = []
2573 n = expr
2574 while isinstance(n, ast.Attribute):
2575 a.append(n.attr)
2576 n = n.value
2577 if not isinstance(n, ast.Name):
2578 fail("Malformed default value (looked like a Python constant)")
2579 a.append(n.id)
2580 py_default = ".".join(reversed(a))
Larry Hastings16c51912014-01-07 11:53:01 -08002581 kwargs["py_default"] = py_default
Larry Hastings4a55fc52014-01-12 11:09:57 -08002582 value = eval(py_default)
Larry Hastings31826802013-10-19 00:09:25 -07002583 else:
2584 value = ast.literal_eval(expr)
2585 else:
2586 value = unspecified
2587
Larry Hastings31826802013-10-19 00:09:25 -07002588 dict = legacy_converters if legacy else converters
2589 legacy_str = "legacy " if legacy else ""
2590 if name not in dict:
2591 fail('{} is not a valid {}converter'.format(name, legacy_str))
2592 converter = dict[name](parameter_name, self.function, value, **kwargs)
2593
Larry Hastingsebdcb502013-11-23 14:54:00 -08002594 # special case: if it's the self converter,
2595 # don't actually add it to the parameter list
2596 if isinstance(converter, self_converter):
2597 if self.function.parameters or (self.parameter_state != self.ps_required):
2598 fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.")
2599 if self.function.self_converter:
2600 fail("You can't specify the 'self' parameter more than once.")
2601 self.function.self_converter = converter
2602 self.parameter_state = self.ps_start
2603 return
2604
Larry Hastings31826802013-10-19 00:09:25 -07002605 kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD
2606 p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group)
2607 self.function.parameters[parameter_name] = p
2608
2609 def parse_converter(self, annotation):
2610 if isinstance(annotation, ast.Str):
2611 return annotation.s, True, {}
2612
2613 if isinstance(annotation, ast.Name):
2614 return annotation.id, False, {}
2615
Larry Hastings4a55fc52014-01-12 11:09:57 -08002616 if not isinstance(annotation, ast.Call):
2617 fail("Annotations must be either a name, a function call, or a string.")
Larry Hastings31826802013-10-19 00:09:25 -07002618
2619 name = annotation.func.id
2620 kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords}
2621 return name, False, kwargs
2622
2623 def parse_special_symbol(self, symbol):
2624 if self.parameter_state == self.ps_seen_slash:
2625 fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
2626
2627 if symbol == '*':
2628 if self.keyword_only:
2629 fail("Function " + self.function.name + " uses '*' more than once.")
2630 self.keyword_only = True
2631 elif symbol == '[':
2632 if self.parameter_state in (self.ps_start, self.ps_left_square_before):
2633 self.parameter_state = self.ps_left_square_before
2634 elif self.parameter_state in (self.ps_required, self.ps_group_after):
2635 self.parameter_state = self.ps_group_after
2636 else:
2637 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2638 self.group += 1
2639 elif symbol == ']':
2640 if not self.group:
2641 fail("Function " + self.function.name + " has a ] without a matching [.")
2642 if not any(p.group == self.group for p in self.function.parameters.values()):
2643 fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
2644 self.group -= 1
2645 if self.parameter_state in (self.ps_left_square_before, self.ps_group_before):
2646 self.parameter_state = self.ps_group_before
2647 elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
2648 self.parameter_state = self.ps_right_square_after
2649 else:
2650 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2651 elif symbol == '/':
2652 # ps_required is allowed here, that allows positional-only without option groups
2653 # to work (and have default values!)
2654 if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
2655 fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
2656 if self.keyword_only:
2657 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2658 self.parameter_state = self.ps_seen_slash
2659 # fixup preceeding parameters
2660 for p in self.function.parameters.values():
2661 if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD:
2662 fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
2663 p.kind = inspect.Parameter.POSITIONAL_ONLY
2664
2665 def state_parameter_docstring_start(self, line):
2666 self.parameter_docstring_indent = len(self.indent.margin)
2667 assert self.indent.depth == 3
2668 return self.next(self.state_parameter_docstring, line)
2669
2670 # every line of the docstring must start with at least F spaces,
2671 # where F > P.
2672 # these F spaces will be stripped.
2673 def state_parameter_docstring(self, line):
2674 stripped = line.strip()
2675 if stripped.startswith('#'):
2676 return
2677
2678 indent = self.indent.measure(line)
2679 if indent < self.parameter_docstring_indent:
2680 self.indent.infer(line)
2681 assert self.indent.depth < 3
2682 if self.indent.depth == 2:
2683 # back to a parameter
2684 return self.next(self.state_parameter, line)
2685 assert self.indent.depth == 1
2686 return self.next(self.state_function_docstring, line)
2687
2688 assert self.function.parameters
2689 last_parameter = next(reversed(list(self.function.parameters.values())))
2690
2691 new_docstring = last_parameter.docstring
2692
2693 if new_docstring:
2694 new_docstring += '\n'
2695 if stripped:
2696 new_docstring += self.indent.dedent(line)
2697
2698 last_parameter.docstring = new_docstring
2699
2700 # the final stanza of the DSL is the docstring.
2701 def state_function_docstring(self, line):
Larry Hastings31826802013-10-19 00:09:25 -07002702 if self.group:
2703 fail("Function " + self.function.name + " has a ] without a matching [.")
2704
2705 stripped = line.strip()
2706 if stripped.startswith('#'):
2707 return
2708
2709 new_docstring = self.function.docstring
2710 if new_docstring:
2711 new_docstring += "\n"
2712 if stripped:
2713 line = self.indent.dedent(line).rstrip()
2714 else:
2715 line = ''
2716 new_docstring += line
2717 self.function.docstring = new_docstring
2718
2719 def format_docstring(self):
2720 f = self.function
2721
2722 add, output = text_accumulator()
2723 parameters = list(f.parameters.values())
2724
2725 ##
2726 ## docstring first line
2727 ##
2728
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002729 add(f.name)
Larry Hastings31826802013-10-19 00:09:25 -07002730 add('(')
2731
2732 # populate "right_bracket_count" field for every parameter
2733 if parameters:
2734 # for now, the only way Clinic supports positional-only parameters
2735 # is if all of them are positional-only.
2736 positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters]
2737 if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY:
2738 assert all(positional_only_parameters)
2739 for p in parameters:
2740 p.right_bracket_count = abs(p.group)
2741 else:
2742 # don't put any right brackets around non-positional-only parameters, ever.
2743 for p in parameters:
2744 p.right_bracket_count = 0
2745
2746 right_bracket_count = 0
2747
2748 def fix_right_bracket_count(desired):
2749 nonlocal right_bracket_count
2750 s = ''
2751 while right_bracket_count < desired:
2752 s += '['
2753 right_bracket_count += 1
2754 while right_bracket_count > desired:
2755 s += ']'
2756 right_bracket_count -= 1
2757 return s
2758
2759 added_star = False
2760 add_comma = False
2761
2762 for p in parameters:
2763 assert p.name
2764
2765 if p.is_keyword_only() and not added_star:
2766 added_star = True
2767 if add_comma:
2768 add(', ')
2769 add('*')
2770
2771 a = [p.name]
2772 if p.converter.is_optional():
2773 a.append('=')
2774 value = p.converter.default
2775 a.append(p.converter.doc_default)
2776 s = fix_right_bracket_count(p.right_bracket_count)
2777 s += "".join(a)
2778 if add_comma:
2779 add(', ')
2780 add(s)
2781 add_comma = True
2782
2783 add(fix_right_bracket_count(0))
2784 add(')')
2785
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002786 # if f.return_converter.doc_default:
2787 # add(' -> ')
2788 # add(f.return_converter.doc_default)
Larry Hastings31826802013-10-19 00:09:25 -07002789
2790 docstring_first_line = output()
2791
2792 # now fix up the places where the brackets look wrong
2793 docstring_first_line = docstring_first_line.replace(', ]', ',] ')
2794
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002795 # okay. now we're officially building the "parameters" section.
Larry Hastings31826802013-10-19 00:09:25 -07002796 # create substitution text for {parameters}
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002797 spacer_line = False
Larry Hastings31826802013-10-19 00:09:25 -07002798 for p in parameters:
2799 if not p.docstring.strip():
2800 continue
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002801 if spacer_line:
2802 add('\n')
2803 else:
2804 spacer_line = True
Larry Hastings31826802013-10-19 00:09:25 -07002805 add(" ")
2806 add(p.name)
2807 add('\n')
2808 add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002809 parameters = output()
2810 if parameters:
2811 parameters += '\n'
Larry Hastings31826802013-10-19 00:09:25 -07002812
2813 ##
2814 ## docstring body
2815 ##
2816
2817 docstring = f.docstring.rstrip()
2818 lines = [line.rstrip() for line in docstring.split('\n')]
2819
2820 # Enforce the summary line!
2821 # The first line of a docstring should be a summary of the function.
2822 # It should fit on one line (80 columns? 79 maybe?) and be a paragraph
2823 # by itself.
2824 #
2825 # Argument Clinic enforces the following rule:
2826 # * either the docstring is empty,
2827 # * or it must have a summary line.
2828 #
2829 # Guido said Clinic should enforce this:
2830 # http://mail.python.org/pipermail/python-dev/2013-June/127110.html
2831
2832 if len(lines) >= 2:
2833 if lines[1]:
2834 fail("Docstring for " + f.full_name + " does not have a summary line!\n" +
2835 "Every non-blank function docstring must start with\n" +
2836 "a single line summary followed by an empty line.")
2837 elif len(lines) == 1:
2838 # the docstring is only one line right now--the summary line.
2839 # add an empty line after the summary line so we have space
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002840 # between it and the {parameters} we're about to add.
Larry Hastings31826802013-10-19 00:09:25 -07002841 lines.append('')
2842
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002843 parameters_marker_count = len(docstring.split('{parameters}')) - 1
2844 if parameters_marker_count > 1:
2845 fail('You may not specify {parameters} more than once in a docstring!')
2846
2847 if not parameters_marker_count:
2848 # insert after summary line
2849 lines.insert(2, '{parameters}')
2850
2851 # insert at front of docstring
2852 lines.insert(0, docstring_first_line)
Larry Hastings31826802013-10-19 00:09:25 -07002853
2854 docstring = "\n".join(lines)
2855
2856 add(docstring)
2857 docstring = output()
2858
Larry Hastings44e2eaa2013-11-23 15:37:55 -08002859 docstring = linear_format(docstring, parameters=parameters)
Larry Hastings31826802013-10-19 00:09:25 -07002860 docstring = docstring.rstrip()
2861
2862 return docstring
2863
2864 def state_terminal(self, line):
2865 """
2866 Called when processing the block is done.
2867 """
2868 assert not line
2869
2870 if not self.function:
2871 return
2872
Larry Hastings6d2ea212014-01-05 02:50:45 -08002873 if not self.function.self_converter:
2874 self.function.self_converter = self_converter("self", self.function)
2875
Larry Hastings31826802013-10-19 00:09:25 -07002876 if self.keyword_only:
2877 values = self.function.parameters.values()
2878 if not values:
2879 no_parameter_after_star = True
2880 else:
2881 last_parameter = next(reversed(list(values)))
2882 no_parameter_after_star = last_parameter.kind != inspect.Parameter.KEYWORD_ONLY
2883 if no_parameter_after_star:
2884 fail("Function " + self.function.name + " specifies '*' without any parameters afterwards.")
2885
2886 # remove trailing whitespace from all parameter docstrings
2887 for name, value in self.function.parameters.items():
2888 if not value:
2889 continue
2890 value.docstring = value.docstring.rstrip()
2891
2892 self.function.docstring = self.format_docstring()
2893
2894
2895# maps strings to callables.
2896# the callable should return an object
2897# that implements the clinic parser
2898# interface (__init__ and parse).
2899#
2900# example parsers:
2901# "clinic", handles the Clinic DSL
2902# "python", handles running Python code
2903#
2904parsers = {'clinic' : DSLParser, 'python': PythonParser}
2905
2906
2907clinic = None
2908
2909
2910def main(argv):
2911 import sys
2912
2913 if sys.version_info.major < 3 or sys.version_info.minor < 3:
2914 sys.exit("Error: clinic.py requires Python 3.3 or greater.")
2915
2916 import argparse
2917 cmdline = argparse.ArgumentParser()
2918 cmdline.add_argument("-f", "--force", action='store_true')
2919 cmdline.add_argument("-o", "--output", type=str)
2920 cmdline.add_argument("--converters", action='store_true')
Larry Hastingsdcd340e2013-11-23 14:58:45 -08002921 cmdline.add_argument("--make", action='store_true')
Larry Hastings31826802013-10-19 00:09:25 -07002922 cmdline.add_argument("filename", type=str, nargs="*")
2923 ns = cmdline.parse_args(argv)
2924
2925 if ns.converters:
2926 if ns.filename:
2927 print("Usage error: can't specify --converters and a filename at the same time.")
2928 print()
2929 cmdline.print_usage()
2930 sys.exit(-1)
2931 converters = []
2932 return_converters = []
2933 ignored = set("""
2934 add_c_converter
2935 add_c_return_converter
2936 add_default_legacy_c_converter
2937 add_legacy_c_converter
2938 """.strip().split())
2939 module = globals()
2940 for name in module:
2941 for suffix, ids in (
2942 ("_return_converter", return_converters),
2943 ("_converter", converters),
2944 ):
2945 if name in ignored:
2946 continue
2947 if name.endswith(suffix):
2948 ids.append((name, name[:-len(suffix)]))
2949 break
2950 print()
2951
2952 print("Legacy converters:")
2953 legacy = sorted(legacy_converters)
2954 print(' ' + ' '.join(c for c in legacy if c[0].isupper()))
2955 print(' ' + ' '.join(c for c in legacy if c[0].islower()))
2956 print()
2957
2958 for title, attribute, ids in (
2959 ("Converters", 'converter_init', converters),
2960 ("Return converters", 'return_converter_init', return_converters),
2961 ):
2962 print(title + ":")
2963 longest = -1
2964 for name, short_name in ids:
2965 longest = max(longest, len(short_name))
2966 for name, short_name in sorted(ids, key=lambda x: x[1].lower()):
2967 cls = module[name]
2968 callable = getattr(cls, attribute, None)
2969 if not callable:
2970 continue
2971 signature = inspect.signature(callable)
2972 parameters = []
2973 for parameter_name, parameter in signature.parameters.items():
2974 if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2975 if parameter.default != inspect.Parameter.empty:
2976 s = '{}={!r}'.format(parameter_name, parameter.default)
2977 else:
2978 s = parameter_name
2979 parameters.append(s)
2980 print(' {}({})'.format(short_name, ', '.join(parameters)))
2981 # add_comma = False
2982 # for parameter_name, parameter in signature.parameters.items():
2983 # if parameter.kind == inspect.Parameter.KEYWORD_ONLY:
2984 # if add_comma:
2985 # parameters.append(', ')
2986 # else:
2987 # add_comma = True
2988 # s = parameter_name
2989 # if parameter.default != inspect.Parameter.empty:
2990 # s += '=' + repr(parameter.default)
2991 # parameters.append(s)
2992 # parameters.append(')')
2993
2994 # print(" ", short_name + "".join(parameters))
2995 print()
Larry Hastings78cf85c2014-01-04 12:44:57 -08002996 print("All converters also accept (doc_default=None, required=False, annotation=None).")
Larry Hastings31826802013-10-19 00:09:25 -07002997 print("All return converters also accept (doc_default=None).")
2998 sys.exit(0)
2999
Larry Hastingsdcd340e2013-11-23 14:58:45 -08003000 if ns.make:
3001 if ns.output or ns.filename:
3002 print("Usage error: can't use -o or filenames with --make.")
3003 print()
3004 cmdline.print_usage()
3005 sys.exit(-1)
3006 for root, dirs, files in os.walk('.'):
3007 for rcs_dir in ('.svn', '.git', '.hg'):
3008 if rcs_dir in dirs:
3009 dirs.remove(rcs_dir)
3010 for filename in files:
3011 if not filename.endswith('.c'):
3012 continue
3013 path = os.path.join(root, filename)
3014 parse_file(path, verify=not ns.force)
3015 return
3016
Larry Hastings31826802013-10-19 00:09:25 -07003017 if not ns.filename:
3018 cmdline.print_usage()
3019 sys.exit(-1)
3020
3021 if ns.output and len(ns.filename) > 1:
3022 print("Usage error: can't use -o with multiple filenames.")
3023 print()
3024 cmdline.print_usage()
3025 sys.exit(-1)
3026
3027 for filename in ns.filename:
3028 parse_file(filename, output=ns.output, verify=not ns.force)
3029
3030
3031if __name__ == "__main__":
3032 sys.exit(main(sys.argv[1:]))