Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9076fb0

Browse files
authored
[mypyc] Improve documentation in mypyc.primitives (#8569)
The aim is to give at least a short comment for all non-trivial ops. Add docstrings to all modules that don't have them. Also minor fix to `py_call_with_kwargs_op`.
1 parent 828a9eb commit 9076fb0

11 files changed

Lines changed: 242 additions & 32 deletions

File tree

mypyc/ir/rtypes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ def deserialize(cls, data: JsonDict, ctx: 'DeserMaps') -> 'RTuple':
396396
return RTuple(types)
397397

398398

399+
# Exception tuple: (exception class, exception instance, traceback object)
399400
exc_rtuple = RTuple([object_rprimitive, object_rprimitive, object_rprimitive])
400401

401402

mypyc/primitives/dict_ops.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,38 @@
1111
)
1212

1313

14+
# Get the 'dict' type object.
1415
name_ref_op('builtins.dict',
1516
result_type=object_rprimitive,
1617
error_kind=ERR_NEVER,
1718
emit=simple_emit('{dest} = (PyObject *)&PyDict_Type;'),
1819
is_borrowed=True)
1920

21+
# dict[key]
2022
dict_get_item_op = method_op(
2123
name='__getitem__',
2224
arg_types=[dict_rprimitive, object_rprimitive],
2325
result_type=object_rprimitive,
2426
error_kind=ERR_MAGIC,
2527
emit=call_emit('CPyDict_GetItem'))
2628

27-
29+
# dict[key] = value
2830
dict_set_item_op = method_op(
2931
name='__setitem__',
3032
arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
3133
result_type=bool_rprimitive,
3234
error_kind=ERR_FALSE,
3335
emit=call_negative_bool_emit('CPyDict_SetItem'))
3436

35-
37+
# key in dict
3638
binary_op(op='in',
3739
arg_types=[object_rprimitive, dict_rprimitive],
3840
result_type=bool_rprimitive,
3941
error_kind=ERR_MAGIC,
4042
format_str='{dest} = {args[0]} in {args[1]} :: dict',
4143
emit=negative_int_emit('{dest} = PyDict_Contains({args[1]}, {args[0]});'))
4244

45+
# dict1.update(dict2)
4346
dict_update_op = method_op(
4447
name='update',
4548
arg_types=[dict_rprimitive, dict_rprimitive],
@@ -48,27 +51,32 @@
4851
emit=call_negative_bool_emit('CPyDict_Update'),
4952
priority=2)
5053

54+
# Operation used for **value in dict displays.
55+
# This is mostly like dict.update(obj), but has customized error handling.
5156
dict_update_in_display_op = custom_op(
5257
arg_types=[dict_rprimitive, dict_rprimitive],
5358
result_type=bool_rprimitive,
5459
error_kind=ERR_FALSE,
5560
emit=call_negative_bool_emit('CPyDict_UpdateInDisplay'),
5661
format_str='{dest} = {args[0]}.update({args[1]}) (display) :: dict',)
5762

63+
# dict.update(obj)
5864
method_op(
5965
name='update',
6066
arg_types=[dict_rprimitive, object_rprimitive],
6167
result_type=bool_rprimitive,
6268
error_kind=ERR_FALSE,
6369
emit=simple_emit('{dest} = CPyDict_UpdateFromAny({args[0]}, {args[1]}) != -1;'))
6470

71+
# dict.get(key, default)
6572
method_op(
6673
name='get',
6774
arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
6875
result_type=object_rprimitive,
6976
error_kind=ERR_MAGIC,
7077
emit=call_emit('CPyDict_Get'))
7178

79+
# dict.get(key)
7280
method_op(
7381
name='get',
7482
arg_types=[dict_rprimitive, object_rprimitive],
@@ -85,6 +93,8 @@ def emit_new_dict(emitter: EmitterInterface, args: List[str], dest: str) -> None
8593
emitter.emit_line('%s = CPyDict_Build(%s, %s);' % (dest, len(args) // 2, ', '.join(args)))
8694

8795

96+
# Construct a dictionary from keys and values.
97+
# Arguments are (key1, value1, ..., keyN, valueN).
8898
new_dict_op = custom_op(
8999
name='builtins.dict',
90100
arg_types=[object_rprimitive],
@@ -94,6 +104,7 @@ def emit_new_dict(emitter: EmitterInterface, args: List[str], dest: str) -> None
94104
error_kind=ERR_MAGIC,
95105
emit=emit_new_dict)
96106

107+
# Construct a dictionary from another dictionary.
97108
func_op(
98109
name='builtins.dict',
99110
arg_types=[dict_rprimitive],
@@ -102,6 +113,7 @@ def emit_new_dict(emitter: EmitterInterface, args: List[str], dest: str) -> None
102113
emit=call_emit('PyDict_Copy'),
103114
priority=2)
104115

116+
# Generic one-argument dict constructor: dict(obj)
105117
func_op(
106118
name='builtins.dict',
107119
arg_types=[object_rprimitive],
@@ -117,6 +129,7 @@ def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
117129
emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp))
118130

119131

132+
# len(dict)
120133
func_op(name='builtins.len',
121134
arg_types=[dict_rprimitive],
122135
result_type=int_rprimitive,

mypyc/primitives/exc_ops.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
simple_emit, custom_op,
77
)
88

9+
# If the argument is a class, raise an instance of the class. Otherwise, assume
10+
# that the argument is an exception object, and raise it.
11+
#
912
# TODO: Making this raise conditionally is kind of hokey.
1013
raise_exception_op = custom_op(
1114
arg_types=[object_rprimitive],
@@ -14,41 +17,49 @@
1417
format_str='raise_exception({args[0]}); {dest} = 0',
1518
emit=simple_emit('CPy_Raise({args[0]}); {dest} = 0;'))
1619

20+
# Raise StopIteration exception with the specified value (which can be NULL).
1721
set_stop_iteration_value = custom_op(
1822
arg_types=[object_rprimitive],
1923
result_type=bool_rprimitive,
2024
error_kind=ERR_FALSE,
2125
format_str='set_stop_iteration_value({args[0]}); {dest} = 0',
2226
emit=simple_emit('CPyGen_SetStopIterationValue({args[0]}); {dest} = 0;'))
2327

28+
# Raise exception with traceback.
29+
# Arguments are (exception type, exception value, traceback).
2430
raise_exception_with_tb_op = custom_op(
2531
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
2632
result_type=bool_rprimitive,
2733
error_kind=ERR_FALSE,
2834
format_str='raise_exception_with_tb({args[0]}, {args[1]}, {args[2]}); {dest} = 0',
2935
emit=simple_emit('CPyErr_SetObjectAndTraceback({args[0]}, {args[1]}, {args[2]}); {dest} = 0;'))
3036

37+
# Reraise the currently raised exception.
3138
reraise_exception_op = custom_op(
3239
arg_types=[],
3340
result_type=bool_rprimitive,
3441
error_kind=ERR_FALSE,
3542
format_str='reraise_exc; {dest} = 0',
3643
emit=simple_emit('CPy_Reraise(); {dest} = 0;'))
3744

45+
# Propagate exception if the CPython error indicator is set (an exception was raised).
3846
no_err_occurred_op = custom_op(
3947
arg_types=[],
4048
result_type=bool_rprimitive,
4149
error_kind=ERR_FALSE,
4250
format_str='{dest} = no_err_occurred',
4351
emit=simple_emit('{dest} = (PyErr_Occurred() == NULL);'))
4452

53+
# Assert that the error indicator has been set.
4554
assert_err_occured_op = custom_op(
4655
arg_types=[],
4756
result_type=void_rtype,
4857
error_kind=ERR_NEVER,
4958
format_str='assert_err_occurred',
5059
emit=simple_emit('assert(PyErr_Occurred() != NULL && "failure w/o err!");'))
5160

61+
# Keep propagating a raised exception by unconditionally giving an error value.
62+
# This doesn't actually raise an exception.
5263
keep_propagating_op = custom_op(
5364
arg_types=[],
5465
result_type=bool_rprimitive,
@@ -67,7 +78,7 @@
6778
format_str='{dest} = error_catch',
6879
emit=simple_emit('CPy_CatchError(&{dest}.f0, &{dest}.f1, &{dest}.f2);'))
6980

70-
# Restore an old "currently handled exception" returned from
81+
# Restore an old "currently handled exception" returned from.
7182
# error_catch (by sticking it into sys.exc_info())
7283
restore_exc_info_op = custom_op(
7384
arg_types=[exc_rtuple],
@@ -92,6 +103,7 @@
92103
format_str='{dest} = get_exc_value',
93104
emit=simple_emit('{dest} = CPy_GetExcValue();'))
94105

106+
# Get exception info (exception type, exception instance, traceback object).
95107
get_exc_info_op = custom_op(
96108
arg_types=[],
97109
result_type=exc_rtuple,

mypyc/primitives/generic_ops.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
These just call the relevant Python C API function or a thin wrapper
44
around an API function. Most of these also have faster, specialized
55
ops that operate on some more specific types.
6+
7+
Many of these ops are given a low priority (0) so that specialized ops
8+
will take precedence. If your specialized op doesn't seem to be used,
9+
check that the priorities are configured properly.
610
"""
711

812
from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, ERR_FALSE
@@ -13,6 +17,8 @@
1317
)
1418

1519

20+
# Binary operations
21+
1622
for op, opid in [('==', 'Py_EQ'),
1723
('!=', 'Py_NE'),
1824
('<', 'Py_LT'),
@@ -92,6 +98,9 @@
9298
emit=simple_emit('{dest} = {args[0]} != {args[1]};'),
9399
priority=0)
94100

101+
102+
# Unary operations
103+
95104
for op, funcname in [('-', 'PyNumber_Negative'),
96105
('+', 'PyNumber_Positive'),
97106
('~', 'PyNumber_Invert')]:
@@ -110,34 +119,40 @@
110119
emit=call_negative_magic_emit('PyObject_Not'),
111120
priority=0)
112121

122+
123+
# obj1[obj2]
113124
method_op('__getitem__',
114125
arg_types=[object_rprimitive, object_rprimitive],
115126
result_type=object_rprimitive,
116127
error_kind=ERR_MAGIC,
117128
emit=call_emit('PyObject_GetItem'),
118129
priority=0)
119130

131+
# obj1[obj2] = obj3
120132
method_op('__setitem__',
121133
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
122134
result_type=bool_rprimitive,
123135
error_kind=ERR_FALSE,
124136
emit=call_negative_bool_emit('PyObject_SetItem'),
125137
priority=0)
126138

139+
# del obj1[obj2]
127140
method_op('__delitem__',
128141
arg_types=[object_rprimitive, object_rprimitive],
129142
result_type=bool_rprimitive,
130143
error_kind=ERR_FALSE,
131144
emit=call_negative_bool_emit('PyObject_DelItem'),
132145
priority=0)
133146

147+
# hash(obj)
134148
func_op(
135149
name='builtins.hash',
136150
arg_types=[object_rprimitive],
137151
result_type=int_rprimitive,
138152
error_kind=ERR_MAGIC,
139153
emit=call_emit('CPyObject_Hash'))
140154

155+
# getattr(obj, attr)
141156
py_getattr_op = func_op(
142157
name='builtins.getattr',
143158
arg_types=[object_rprimitive, object_rprimitive],
@@ -146,6 +161,7 @@
146161
emit=call_emit('PyObject_GetAttr')
147162
)
148163

164+
# getattr(obj, attr, default)
149165
func_op(
150166
name='builtins.getattr',
151167
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
@@ -154,6 +170,7 @@
154170
emit=call_emit('CPyObject_GetAttr3')
155171
)
156172

173+
# setattr(obj, attr, value)
157174
py_setattr_op = func_op(
158175
name='builtins.setattr',
159176
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
@@ -162,6 +179,7 @@
162179
emit=call_negative_bool_emit('PyObject_SetAttr')
163180
)
164181

182+
# hasattr(obj, attr)
165183
py_hasattr_op = func_op(
166184
name='builtins.hasattr',
167185
arg_types=[object_rprimitive, object_rprimitive],
@@ -170,6 +188,7 @@
170188
emit=call_emit('PyObject_HasAttr')
171189
)
172190

191+
# del obj.attr
173192
py_delattr_op = func_op(
174193
name='builtins.delattr',
175194
arg_types=[object_rprimitive, object_rprimitive],
@@ -178,6 +197,8 @@
178197
emit=call_negative_bool_emit('PyObject_DelAttr')
179198
)
180199

200+
# Call callable object with N positional arguments: func(arg1, ..., argN)
201+
# Arguments are (func, arg1, ..., argN).
181202
py_call_op = custom_op(
182203
arg_types=[object_rprimitive],
183204
result_type=object_rprimitive,
@@ -186,14 +207,17 @@
186207
format_str='{dest} = py_call({comma_args})',
187208
emit=simple_emit('{dest} = PyObject_CallFunctionObjArgs({comma_args}, NULL);'))
188209

210+
# Call callable object with positional + keyword args: func(*args, **kwargs)
211+
# Arguments are (func, *args tuple, **kwargs dict).
189212
py_call_with_kwargs_op = custom_op(
190-
arg_types=[object_rprimitive],
213+
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
191214
result_type=object_rprimitive,
192-
is_var_arg=True,
193215
error_kind=ERR_MAGIC,
194216
format_str='{dest} = py_call_with_kwargs({args[0]}, {args[1]}, {args[2]})',
195217
emit=call_emit('PyObject_Call'))
196218

219+
# Call method with positional arguments: obj.method(arg1, ...)
220+
# Arguments are (object, attribute name, arg1, ...).
197221
py_method_call_op = custom_op(
198222
arg_types=[object_rprimitive],
199223
result_type=object_rprimitive,
@@ -202,19 +226,23 @@
202226
format_str='{dest} = py_method_call({comma_args})',
203227
emit=simple_emit('{dest} = PyObject_CallMethodObjArgs({comma_args}, NULL);'))
204228

229+
# len(obj)
205230
func_op(name='builtins.len',
206231
arg_types=[object_rprimitive],
207232
result_type=int_rprimitive,
208233
error_kind=ERR_NEVER,
209234
emit=call_emit('CPyObject_Size'),
210235
priority=0)
211236

237+
# iter(obj)
212238
iter_op = func_op(name='builtins.iter',
213239
arg_types=[object_rprimitive],
214240
result_type=object_rprimitive,
215241
error_kind=ERR_MAGIC,
216242
emit=call_emit('PyObject_GetIter'))
217243

244+
# next(iterator)
245+
#
218246
# Although the error_kind is set to be ERR_NEVER, this can actually
219247
# return NULL, and thus it must be checked using Branch.IS_ERROR.
220248
next_op = custom_op(name='next',
@@ -223,6 +251,8 @@
223251
error_kind=ERR_NEVER,
224252
emit=call_emit('PyIter_Next'))
225253

254+
# next(iterator)
255+
#
226256
# Do a next, don't swallow StopIteration, but also don't propagate an
227257
# error. (N.B: This can still return NULL without an error to
228258
# represent an implicit StopIteration, but if StopIteration is

0 commit comments

Comments
 (0)