@@ -3,21 +3,28 @@ use super::objdict::PyDictRef;
3
3
use super :: objstr:: PyStringRef ;
4
4
use super :: objtuple:: PyTupleRef ;
5
5
use super :: objtype:: PyClassRef ;
6
+ use crate :: bytecode;
6
7
use crate :: descriptor:: PyBuiltinDescriptor ;
8
+ use crate :: frame:: Frame ;
7
9
use crate :: function:: { OptionalArg , PyFuncArgs } ;
8
- use crate :: pyobject:: { IdProtocol , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol } ;
10
+ use crate :: obj:: objcoroutine:: PyCoroutine ;
11
+ use crate :: obj:: objgenerator:: PyGenerator ;
12
+ use crate :: pyobject:: {
13
+ IdProtocol , ItemProtocol , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue ,
14
+ TypeProtocol ,
15
+ } ;
9
16
use crate :: scope:: Scope ;
10
17
use crate :: vm:: VirtualMachine ;
11
18
12
19
pub type PyFunctionRef = PyRef < PyFunction > ;
13
20
21
+ #[ pyclass]
14
22
#[ derive( Debug ) ]
15
23
pub struct PyFunction {
16
- // TODO: these shouldn't be public
17
- pub code : PyCodeRef ,
18
- pub scope : Scope ,
19
- pub defaults : Option < PyTupleRef > ,
20
- pub kw_only_defaults : Option < PyDictRef > ,
24
+ code : PyCodeRef ,
25
+ scope : Scope ,
26
+ defaults : Option < PyTupleRef > ,
27
+ kw_only_defaults : Option < PyDictRef > ,
21
28
}
22
29
23
30
impl PyBuiltinDescriptor for PyFunction {
@@ -49,6 +56,182 @@ impl PyFunction {
49
56
kw_only_defaults,
50
57
}
51
58
}
59
+
60
+ pub fn scope ( & self ) -> & Scope {
61
+ & self . scope
62
+ }
63
+
64
+ fn fill_locals_from_args (
65
+ & self ,
66
+ code_object : & bytecode:: CodeObject ,
67
+ locals : & PyDictRef ,
68
+ func_args : PyFuncArgs ,
69
+ vm : & VirtualMachine ,
70
+ ) -> PyResult < ( ) > {
71
+ let nargs = func_args. args . len ( ) ;
72
+ let nexpected_args = code_object. arg_names . len ( ) ;
73
+
74
+ // This parses the arguments from args and kwargs into
75
+ // the proper variables keeping into account default values
76
+ // and starargs and kwargs.
77
+ // See also: PyEval_EvalCodeWithName in cpython:
78
+ // https://github.com/python/cpython/blob/master/Python/ceval.c#L3681
79
+
80
+ let n = if nargs > nexpected_args {
81
+ nexpected_args
82
+ } else {
83
+ nargs
84
+ } ;
85
+
86
+ // Copy positional arguments into local variables
87
+ for i in 0 ..n {
88
+ let arg_name = & code_object. arg_names [ i] ;
89
+ let arg = & func_args. args [ i] ;
90
+ locals. set_item ( arg_name, arg. clone ( ) , vm) ?;
91
+ }
92
+
93
+ // Pack other positional arguments in to *args:
94
+ match code_object. varargs {
95
+ bytecode:: Varargs :: Named ( ref vararg_name) => {
96
+ let mut last_args = vec ! [ ] ;
97
+ for i in n..nargs {
98
+ let arg = & func_args. args [ i] ;
99
+ last_args. push ( arg. clone ( ) ) ;
100
+ }
101
+ let vararg_value = vm. ctx . new_tuple ( last_args) ;
102
+
103
+ locals. set_item ( vararg_name, vararg_value, vm) ?;
104
+ }
105
+ bytecode:: Varargs :: Unnamed | bytecode:: Varargs :: None => {
106
+ // Check the number of positional arguments
107
+ if nargs > nexpected_args {
108
+ return Err ( vm. new_type_error ( format ! (
109
+ "Expected {} arguments (got: {})" ,
110
+ nexpected_args, nargs
111
+ ) ) ) ;
112
+ }
113
+ }
114
+ }
115
+
116
+ // Do we support `**kwargs` ?
117
+ let kwargs = match code_object. varkeywords {
118
+ bytecode:: Varargs :: Named ( ref kwargs_name) => {
119
+ let d = vm. ctx . new_dict ( ) ;
120
+ locals. set_item ( kwargs_name, d. as_object ( ) . clone ( ) , vm) ?;
121
+ Some ( d)
122
+ }
123
+ bytecode:: Varargs :: Unnamed => Some ( vm. ctx . new_dict ( ) ) ,
124
+ bytecode:: Varargs :: None => None ,
125
+ } ;
126
+
127
+ // Handle keyword arguments
128
+ for ( name, value) in func_args. kwargs {
129
+ // Check if we have a parameter with this name:
130
+ if code_object. arg_names . contains ( & name) || code_object. kwonlyarg_names . contains ( & name)
131
+ {
132
+ if locals. contains_key ( & name, vm) {
133
+ return Err (
134
+ vm. new_type_error ( format ! ( "Got multiple values for argument '{}'" , name) )
135
+ ) ;
136
+ }
137
+
138
+ locals. set_item ( & name, value, vm) ?;
139
+ } else if let Some ( d) = & kwargs {
140
+ d. set_item ( & name, value, vm) ?;
141
+ } else {
142
+ return Err (
143
+ vm. new_type_error ( format ! ( "Got an unexpected keyword argument '{}'" , name) )
144
+ ) ;
145
+ }
146
+ }
147
+
148
+ // Add missing positional arguments, if we have fewer positional arguments than the
149
+ // function definition calls for
150
+ if nargs < nexpected_args {
151
+ let num_defaults_available = self . defaults . as_ref ( ) . map_or ( 0 , |d| d. as_slice ( ) . len ( ) ) ;
152
+
153
+ // Given the number of defaults available, check all the arguments for which we
154
+ // _don't_ have defaults; if any are missing, raise an exception
155
+ let required_args = nexpected_args - num_defaults_available;
156
+ let mut missing = vec ! [ ] ;
157
+ for i in 0 ..required_args {
158
+ let variable_name = & code_object. arg_names [ i] ;
159
+ if !locals. contains_key ( variable_name, vm) {
160
+ missing. push ( variable_name)
161
+ }
162
+ }
163
+ if !missing. is_empty ( ) {
164
+ return Err ( vm. new_type_error ( format ! (
165
+ "Missing {} required positional arguments: {:?}" ,
166
+ missing. len( ) ,
167
+ missing
168
+ ) ) ) ;
169
+ }
170
+ if let Some ( defaults) = & self . defaults {
171
+ let defaults = defaults. as_slice ( ) ;
172
+ // We have sufficient defaults, so iterate over the corresponding names and use
173
+ // the default if we don't already have a value
174
+ for ( default_index, i) in ( required_args..nexpected_args) . enumerate ( ) {
175
+ let arg_name = & code_object. arg_names [ i] ;
176
+ if !locals. contains_key ( arg_name, vm) {
177
+ locals. set_item ( arg_name, defaults[ default_index] . clone ( ) , vm) ?;
178
+ }
179
+ }
180
+ }
181
+ } ;
182
+
183
+ // Check if kw only arguments are all present:
184
+ for arg_name in & code_object. kwonlyarg_names {
185
+ if !locals. contains_key ( arg_name, vm) {
186
+ if let Some ( kw_only_defaults) = & self . kw_only_defaults {
187
+ if let Some ( default) = kw_only_defaults. get_item_option ( arg_name, vm) ? {
188
+ locals. set_item ( arg_name, default, vm) ?;
189
+ continue ;
190
+ }
191
+ }
192
+
193
+ // No default value and not specified.
194
+ return Err (
195
+ vm. new_type_error ( format ! ( "Missing required kw only argument: '{}'" , arg_name) )
196
+ ) ;
197
+ }
198
+ }
199
+
200
+ Ok ( ( ) )
201
+ }
202
+
203
+ pub fn invoke_with_scope (
204
+ & self ,
205
+ func_args : PyFuncArgs ,
206
+ scope : & Scope ,
207
+ vm : & VirtualMachine ,
208
+ ) -> PyResult {
209
+ let code = & self . code ;
210
+
211
+ let scope = if self . code . flags . contains ( bytecode:: CodeFlags :: NEW_LOCALS ) {
212
+ scope. new_child_scope ( & vm. ctx )
213
+ } else {
214
+ scope. clone ( )
215
+ } ;
216
+
217
+ self . fill_locals_from_args ( & code, & scope. get_locals ( ) , func_args, vm) ?;
218
+
219
+ // Construct frame:
220
+ let frame = Frame :: new ( code. clone ( ) , scope) . into_ref ( vm) ;
221
+
222
+ // If we have a generator, create a new generator
223
+ if code. flags . contains ( bytecode:: CodeFlags :: IS_GENERATOR ) {
224
+ Ok ( PyGenerator :: new ( frame, vm) . into_object ( ) )
225
+ } else if code. flags . contains ( bytecode:: CodeFlags :: IS_COROUTINE ) {
226
+ Ok ( PyCoroutine :: new ( frame, vm) . into_object ( ) )
227
+ } else {
228
+ vm. run_frame_full ( frame)
229
+ }
230
+ }
231
+
232
+ pub fn invoke ( & self , func_args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult {
233
+ self . invoke_with_scope ( func_args, & self . scope , vm)
234
+ }
52
235
}
53
236
54
237
impl PyValue for PyFunction {
@@ -57,20 +240,25 @@ impl PyValue for PyFunction {
57
240
}
58
241
}
59
242
60
- impl PyFunctionRef {
61
- fn call ( func : PyObjectRef , args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult {
62
- vm. invoke ( & func, args)
243
+ #[ pyimpl]
244
+ impl PyFunction {
245
+ #[ pymethod( name = "__call__" ) ]
246
+ fn call ( zelf : PyObjectRef , args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult {
247
+ vm. invoke ( & zelf, args)
63
248
}
64
249
65
- fn code ( self , _vm : & VirtualMachine ) -> PyCodeRef {
250
+ #[ pyproperty( name = "__code__" ) ]
251
+ fn code ( & self , _vm : & VirtualMachine ) -> PyCodeRef {
66
252
self . code . clone ( )
67
253
}
68
254
69
- fn defaults ( self , _vm : & VirtualMachine ) -> Option < PyTupleRef > {
255
+ #[ pyproperty( name = "__defaults__" ) ]
256
+ fn defaults ( & self , _vm : & VirtualMachine ) -> Option < PyTupleRef > {
70
257
self . defaults . clone ( )
71
258
}
72
259
73
- fn kwdefaults ( self , _vm : & VirtualMachine ) -> Option < PyDictRef > {
260
+ #[ pyproperty( name = "__kwdefaults__" ) ]
261
+ fn kwdefaults ( & self , _vm : & VirtualMachine ) -> Option < PyDictRef > {
74
262
self . kw_only_defaults . clone ( )
75
263
}
76
264
}
@@ -100,13 +288,10 @@ impl PyValue for PyBoundMethod {
100
288
101
289
pub fn init ( context : & PyContext ) {
102
290
let function_type = & context. types . function_type ;
291
+ PyFunction :: extend_class ( context, function_type) ;
103
292
extend_class ! ( context, function_type, {
104
293
"__get__" => context. new_method( PyFunction :: get) ,
105
294
( slot descr_get) => PyFunction :: get,
106
- "__call__" => context. new_method( PyFunctionRef :: call) ,
107
- "__code__" => context. new_property( PyFunctionRef :: code) ,
108
- "__defaults__" => context. new_property( PyFunctionRef :: defaults) ,
109
- "__kwdefaults__" => context. new_property( PyFunctionRef :: kwdefaults) ,
110
295
} ) ;
111
296
112
297
let method_type = & context. types . bound_method_type ;
0 commit comments