1use crate::{
2 builtins::{
3 builtin_func::PyNativeFunction,
4 descriptor::PyMethodDescriptor,
5 tuple::{IntoPyTuple, PyTupleRef},
6 PyBaseException, PyBaseExceptionRef, PyDictRef, PyModule, PyStrRef, PyType, PyTypeRef,
7 },
8 convert::ToPyObject,
9 function::{IntoPyNativeFn, PyMethodFlags},
10 scope::Scope,
11 vm::VirtualMachine,
12 AsObject, Py, PyObject, PyObjectRef, PyRef,
13};
14
15impl VirtualMachine {
17 pub fn new_pyobj(&self, value: impl ToPyObject) -> PyObjectRef {
19 value.to_pyobject(self)
20 }
21
22 pub fn new_tuple(&self, value: impl IntoPyTuple) -> PyTupleRef {
23 value.into_pytuple(self)
24 }
25
26 pub fn new_module(
27 &self,
28 name: &str,
29 dict: PyDictRef,
30 doc: Option<PyStrRef>,
31 ) -> PyRef<PyModule> {
32 let module = PyRef::new_ref(
33 PyModule::new(),
34 self.ctx.types.module_type.to_owned(),
35 Some(dict),
36 );
37 module.init_dict(self.ctx.intern_str(name), doc, self);
38 module
39 }
40
41 pub fn new_scope_with_builtins(&self) -> Scope {
42 Scope::with_builtins(None, self.ctx.new_dict(), self)
43 }
44
45 pub fn new_function<F, FKind>(&self, name: &'static str, f: F) -> PyRef<PyNativeFunction>
46 where
47 F: IntoPyNativeFn<FKind>,
48 {
49 let def = self
50 .ctx
51 .new_method_def(name, f, PyMethodFlags::empty(), None);
52 def.build_function(self)
53 }
54
55 pub fn new_method<F, FKind>(
56 &self,
57 name: &'static str,
58 class: &'static Py<PyType>,
59 f: F,
60 ) -> PyRef<PyMethodDescriptor>
61 where
62 F: IntoPyNativeFn<FKind>,
63 {
64 let def = self
65 .ctx
66 .new_method_def(name, f, PyMethodFlags::METHOD, None);
67 def.build_method(class, self)
68 }
69
70 pub fn new_exception(&self, exc_type: PyTypeRef, args: Vec<PyObjectRef>) -> PyBaseExceptionRef {
76 PyRef::new_ref(
79 PyBaseException::new(args, self),
83 exc_type,
84 Some(self.ctx.new_dict()),
85 )
86 }
87
88 pub fn new_exception_empty(&self, exc_type: PyTypeRef) -> PyBaseExceptionRef {
94 self.new_exception(exc_type, vec![])
95 }
96
97 pub fn new_exception_msg(&self, exc_type: PyTypeRef, msg: String) -> PyBaseExceptionRef {
103 self.new_exception(exc_type, vec![self.ctx.new_str(msg).into()])
104 }
105
106 pub fn new_exception_msg_dict(
112 &self,
113 exc_type: PyTypeRef,
114 msg: String,
115 dict: PyDictRef,
116 ) -> PyBaseExceptionRef {
117 PyRef::new_ref(
118 PyBaseException::new(vec![self.ctx.new_str(msg).into()], self),
122 exc_type,
123 Some(dict),
124 )
125 }
126
127 pub fn new_lookup_error(&self, msg: String) -> PyBaseExceptionRef {
128 let lookup_error = self.ctx.exceptions.lookup_error.to_owned();
129 self.new_exception_msg(lookup_error, msg)
130 }
131
132 pub fn new_attribute_error(&self, msg: String) -> PyBaseExceptionRef {
133 let attribute_error = self.ctx.exceptions.attribute_error.to_owned();
134 self.new_exception_msg(attribute_error, msg)
135 }
136
137 pub fn new_type_error(&self, msg: String) -> PyBaseExceptionRef {
138 let type_error = self.ctx.exceptions.type_error.to_owned();
139 self.new_exception_msg(type_error, msg)
140 }
141
142 pub fn new_name_error(&self, msg: String, name: PyStrRef) -> PyBaseExceptionRef {
143 let name_error_type = self.ctx.exceptions.name_error.to_owned();
144 let name_error = self.new_exception_msg(name_error_type, msg);
145 name_error.as_object().set_attr("name", name, self).unwrap();
146 name_error
147 }
148
149 pub fn new_unsupported_unary_error(&self, a: &PyObject, op: &str) -> PyBaseExceptionRef {
150 self.new_type_error(format!(
151 "bad operand type for {}: '{}'",
152 op,
153 a.class().name()
154 ))
155 }
156
157 pub fn new_unsupported_binop_error(
158 &self,
159 a: &PyObject,
160 b: &PyObject,
161 op: &str,
162 ) -> PyBaseExceptionRef {
163 self.new_type_error(format!(
164 "'{}' not supported between instances of '{}' and '{}'",
165 op,
166 a.class().name(),
167 b.class().name()
168 ))
169 }
170
171 pub fn new_unsupported_ternop_error(
172 &self,
173 a: &PyObject,
174 b: &PyObject,
175 c: &PyObject,
176 op: &str,
177 ) -> PyBaseExceptionRef {
178 self.new_type_error(format!(
179 "Unsupported operand types for '{}': '{}', '{}', and '{}'",
180 op,
181 a.class().name(),
182 b.class().name(),
183 c.class().name()
184 ))
185 }
186
187 pub fn new_os_error(&self, msg: String) -> PyBaseExceptionRef {
188 let os_error = self.ctx.exceptions.os_error.to_owned();
189 self.new_exception_msg(os_error, msg)
190 }
191
192 pub fn new_errno_error(&self, errno: i32, msg: String) -> PyBaseExceptionRef {
193 let vm = self;
194 let exc_type =
195 crate::exceptions::errno_to_exc_type(errno, vm).unwrap_or(vm.ctx.exceptions.os_error);
196
197 let errno_obj = vm.new_pyobj(errno);
198 vm.new_exception(exc_type.to_owned(), vec![errno_obj, vm.new_pyobj(msg)])
199 }
200
201 pub fn new_system_error(&self, msg: String) -> PyBaseExceptionRef {
202 let sys_error = self.ctx.exceptions.system_error.to_owned();
203 self.new_exception_msg(sys_error, msg)
204 }
205
206 pub fn new_unicode_decode_error(&self, msg: String) -> PyBaseExceptionRef {
207 let unicode_decode_error = self.ctx.exceptions.unicode_decode_error.to_owned();
208 self.new_exception_msg(unicode_decode_error, msg)
209 }
210
211 pub fn new_unicode_encode_error(&self, msg: String) -> PyBaseExceptionRef {
212 let unicode_encode_error = self.ctx.exceptions.unicode_encode_error.to_owned();
213 self.new_exception_msg(unicode_encode_error, msg)
214 }
215
216 pub fn new_value_error(&self, msg: String) -> PyBaseExceptionRef {
219 let value_error = self.ctx.exceptions.value_error.to_owned();
220 self.new_exception_msg(value_error, msg)
221 }
222
223 pub fn new_buffer_error(&self, msg: String) -> PyBaseExceptionRef {
224 let buffer_error = self.ctx.exceptions.buffer_error.to_owned();
225 self.new_exception_msg(buffer_error, msg)
226 }
227
228 pub fn new_key_error(&self, obj: PyObjectRef) -> PyBaseExceptionRef {
230 let key_error = self.ctx.exceptions.key_error.to_owned();
231 self.new_exception(key_error, vec![obj])
232 }
233
234 pub fn new_index_error(&self, msg: String) -> PyBaseExceptionRef {
235 let index_error = self.ctx.exceptions.index_error.to_owned();
236 self.new_exception_msg(index_error, msg)
237 }
238
239 pub fn new_not_implemented_error(&self, msg: String) -> PyBaseExceptionRef {
240 let not_implemented_error = self.ctx.exceptions.not_implemented_error.to_owned();
241 self.new_exception_msg(not_implemented_error, msg)
242 }
243
244 pub fn new_recursion_error(&self, msg: String) -> PyBaseExceptionRef {
245 let recursion_error = self.ctx.exceptions.recursion_error.to_owned();
246 self.new_exception_msg(recursion_error, msg)
247 }
248
249 pub fn new_zero_division_error(&self, msg: String) -> PyBaseExceptionRef {
250 let zero_division_error = self.ctx.exceptions.zero_division_error.to_owned();
251 self.new_exception_msg(zero_division_error, msg)
252 }
253
254 pub fn new_overflow_error(&self, msg: String) -> PyBaseExceptionRef {
255 let overflow_error = self.ctx.exceptions.overflow_error.to_owned();
256 self.new_exception_msg(overflow_error, msg)
257 }
258
259 #[cfg(any(feature = "rustpython-parser", feature = "rustpython-codegen"))]
260 pub fn new_syntax_error(
261 &self,
262 error: &crate::compiler::CompileError,
263 source: Option<&str>,
264 ) -> PyBaseExceptionRef {
265 use crate::source_code::SourceLocation;
266
267 let syntax_error_type = match &error.error {
268 #[cfg(feature = "rustpython-parser")]
269 crate::compiler::CompileErrorType::Parse(p) if p.is_indentation_error() => {
270 self.ctx.exceptions.indentation_error
271 }
272 #[cfg(feature = "rustpython-parser")]
273 crate::compiler::CompileErrorType::Parse(p) if p.is_tab_error() => {
274 self.ctx.exceptions.tab_error
275 }
276 _ => self.ctx.exceptions.syntax_error,
277 }
278 .to_owned();
279
280 fn get_statement(source: &str, loc: Option<SourceLocation>) -> Option<String> {
282 let line = source
283 .split('\n')
284 .nth(loc?.row.to_zero_indexed_usize())?
285 .to_owned();
286 Some(line + "\n")
287 }
288
289 let statement = if let Some(source) = source {
290 get_statement(source, error.location)
291 } else {
292 None
293 };
294
295 let syntax_error = self.new_exception_msg(syntax_error_type, error.error.to_string());
296 let (lineno, offset) = error.python_location();
297 let lineno = self.ctx.new_int(lineno);
298 let offset = self.ctx.new_int(offset);
299 syntax_error
300 .as_object()
301 .set_attr("lineno", lineno, self)
302 .unwrap();
303 syntax_error
304 .as_object()
305 .set_attr("offset", offset, self)
306 .unwrap();
307
308 syntax_error
309 .as_object()
310 .set_attr("text", statement.to_pyobject(self), self)
311 .unwrap();
312 syntax_error
313 .as_object()
314 .set_attr(
315 "filename",
316 self.ctx.new_str(error.source_path.clone()),
317 self,
318 )
319 .unwrap();
320 syntax_error
321 }
322
323 pub fn new_import_error(&self, msg: String, name: PyStrRef) -> PyBaseExceptionRef {
324 let import_error = self.ctx.exceptions.import_error.to_owned();
325 let exc = self.new_exception_msg(import_error, msg);
326 exc.as_object().set_attr("name", name, self).unwrap();
327 exc
328 }
329
330 pub fn new_runtime_error(&self, msg: String) -> PyBaseExceptionRef {
331 let runtime_error = self.ctx.exceptions.runtime_error.to_owned();
332 self.new_exception_msg(runtime_error, msg)
333 }
334
335 pub fn new_memory_error(&self, msg: String) -> PyBaseExceptionRef {
336 let memory_error_type = self.ctx.exceptions.memory_error.to_owned();
337 self.new_exception_msg(memory_error_type, msg)
338 }
339
340 pub fn new_stop_iteration(&self, value: Option<PyObjectRef>) -> PyBaseExceptionRef {
341 let dict = self.ctx.new_dict();
342 let args = if let Some(value) = value {
343 dict.set_item("value", value.clone(), self)
345 .expect("dict.__setitem__ never fails");
346 vec![value]
347 } else {
348 Vec::new()
349 };
350
351 PyRef::new_ref(
352 PyBaseException::new(args, self),
353 self.ctx.exceptions.stop_iteration.to_owned(),
354 Some(dict),
355 )
356 }
357
358 fn new_downcast_error(
359 &self,
360 msg: &'static str,
361 error_type: &'static Py<PyType>,
362 class: &Py<PyType>,
363 obj: &PyObject, ) -> PyBaseExceptionRef {
365 let actual_class = obj.class();
366 let actual_type = &*actual_class.name();
367 let expected_type = &*class.name();
368 let msg = format!("Expected {msg} '{expected_type}' but '{actual_type}' found");
369 self.new_exception_msg(error_type.to_owned(), msg)
370 }
371
372 pub(crate) fn new_downcast_runtime_error(
373 &self,
374 class: &Py<PyType>,
375 obj: &impl AsObject,
376 ) -> PyBaseExceptionRef {
377 self.new_downcast_error(
378 "payload",
379 self.ctx.exceptions.runtime_error,
380 class,
381 obj.as_object(),
382 )
383 }
384
385 pub(crate) fn new_downcast_type_error(
386 &self,
387 class: &Py<PyType>,
388 obj: &impl AsObject,
389 ) -> PyBaseExceptionRef {
390 self.new_downcast_error(
391 "type",
392 self.ctx.exceptions.type_error,
393 class,
394 obj.as_object(),
395 )
396 }
397}