forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathops_int.py
98 lines (81 loc) · 3.56 KB
/
ops_int.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from mypyc.ops import (
int_rprimitive, bool_rprimitive, float_rprimitive, object_rprimitive, short_int_rprimitive,
RType, OpDescription,
ERR_NEVER, ERR_MAGIC,
)
from mypyc.ops_primitive import (
name_ref_op, binary_op, unary_op, func_op, custom_op,
simple_emit,
call_emit,
)
# These int constructors produce object_rprimitives that then need to be unboxed
# I guess unboxing ourselves would save a check and branch though?
# For ordinary calls to int() we use a name_ref to the type
name_ref_op('builtins.int',
result_type=object_rprimitive,
error_kind=ERR_NEVER,
emit=simple_emit('{dest} = (PyObject *)&PyLong_Type;'),
is_borrowed=True)
# Convert from a float. We could do a bit better directly.
func_op(
name='builtins.int',
arg_types=[float_rprimitive],
result_type=object_rprimitive,
error_kind=ERR_MAGIC,
emit=call_emit('CPyLong_FromFloat'),
priority=1)
def int_binary_op(op: str, c_func_name: str,
result_type: RType = int_rprimitive,
error_kind: int = ERR_NEVER) -> None:
binary_op(op=op,
arg_types=[int_rprimitive, int_rprimitive],
result_type=result_type,
error_kind=error_kind,
format_str='{dest} = {args[0]} %s {args[1]} :: int' % op,
emit=call_emit(c_func_name))
def int_compare_op(op: str, c_func_name: str) -> None:
int_binary_op(op, c_func_name, bool_rprimitive)
# Generate a straight compare if we know both sides are short
binary_op(op=op,
arg_types=[short_int_rprimitive, short_int_rprimitive],
result_type=bool_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = {args[0]} %s {args[1]} :: short_int' % op,
emit=simple_emit(
'{dest} = (Py_ssize_t){args[0]} %s (Py_ssize_t){args[1]};' % op),
priority=2)
int_binary_op('+', 'CPyTagged_Add')
int_binary_op('-', 'CPyTagged_Subtract')
int_binary_op('*', 'CPyTagged_Multiply')
# Divide and remainder we honestly propagate errors from because they
# can raise ZeroDivisionError
int_binary_op('//', 'CPyTagged_FloorDivide', error_kind=ERR_MAGIC)
int_binary_op('%', 'CPyTagged_Remainder', error_kind=ERR_MAGIC)
# this should work because assignment operators are parsed differently
# and the code in genops that handles it does the assignment
# regardless of whether or not the operator works in place anyway
int_binary_op('+=', 'CPyTagged_Add')
int_binary_op('-=', 'CPyTagged_Subtract')
int_binary_op('*=', 'CPyTagged_Multiply')
int_binary_op('//=', 'CPyTagged_FloorDivide', error_kind=ERR_MAGIC)
int_binary_op('%=', 'CPyTagged_Remainder', error_kind=ERR_MAGIC)
int_compare_op('==', 'CPyTagged_IsEq')
int_compare_op('!=', 'CPyTagged_IsNe')
int_compare_op('<', 'CPyTagged_IsLt')
int_compare_op('<=', 'CPyTagged_IsLe')
int_compare_op('>', 'CPyTagged_IsGt')
int_compare_op('>=', 'CPyTagged_IsGe')
unsafe_short_add = custom_op(
arg_types=[int_rprimitive, int_rprimitive],
result_type=short_int_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = {args[0]} + {args[1]} :: short_int',
emit=simple_emit('{dest} = {args[0]} + {args[1]};'))
def int_unary_op(op: str, c_func_name: str) -> OpDescription:
return unary_op(op=op,
arg_type=int_rprimitive,
result_type=int_rprimitive,
error_kind=ERR_NEVER,
format_str='{dest} = %s{args[0]} :: int' % op,
emit=call_emit(c_func_name))
int_neg_op = int_unary_op('-', 'CPyTagged_Negate')