|
5 | 5 | use super::{PyStrRef, PyTupleRef, PyType, PyTypeRef}; |
6 | 6 | use crate::{ |
7 | 7 | builtins::PyStrInterned, |
8 | | - bytecode::{self, BorrowedConstant, Constant, ConstantBag}, |
| 8 | + bytecode::{self, BorrowedConstant, CodeFlags, Constant, ConstantBag}, |
9 | 9 | class::{PyClassImpl, StaticType}, |
10 | 10 | convert::ToPyObject, |
11 | | - function::FuncArgs, |
| 11 | + function::{FuncArgs, OptionalArg}, |
12 | 12 | AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, |
13 | 13 | }; |
14 | 14 | use num_traits::Zero; |
15 | 15 | use std::{borrow::Borrow, fmt, ops::Deref}; |
16 | 16 |
|
| 17 | +#[derive(FromArgs)] |
| 18 | +pub struct ReplaceArgs { |
| 19 | + #[pyarg(named, optional)] |
| 20 | + co_posonlyargcount: OptionalArg<usize>, |
| 21 | + #[pyarg(named, optional)] |
| 22 | + co_argcount: OptionalArg<usize>, |
| 23 | + #[pyarg(named, optional)] |
| 24 | + co_kwonlyargcount: OptionalArg<usize>, |
| 25 | + #[pyarg(named, optional)] |
| 26 | + co_filename: OptionalArg<PyStrRef>, |
| 27 | + #[pyarg(named, optional)] |
| 28 | + co_firstlineno: OptionalArg<usize>, |
| 29 | + #[pyarg(named, optional)] |
| 30 | + co_consts: OptionalArg<Vec<PyObjectRef>>, |
| 31 | + #[pyarg(named, optional)] |
| 32 | + co_name: OptionalArg<PyStrRef>, |
| 33 | + #[pyarg(named, optional)] |
| 34 | + co_names: OptionalArg<Vec<PyObjectRef>>, |
| 35 | + #[pyarg(named, optional)] |
| 36 | + co_flags: OptionalArg<u16>, |
| 37 | + #[pyarg(named, optional)] |
| 38 | + co_varnames: OptionalArg<Vec<PyObjectRef>>, |
| 39 | +} |
| 40 | + |
17 | 41 | #[derive(Clone)] |
18 | 42 | pub struct Literal(PyObjectRef); |
19 | 43 |
|
@@ -237,6 +261,93 @@ impl PyRef<PyCode> { |
237 | 261 | let varnames = self.code.varnames.iter().map(|s| s.to_object()).collect(); |
238 | 262 | vm.ctx.new_tuple(varnames) |
239 | 263 | } |
| 264 | + |
| 265 | + #[pymethod] |
| 266 | + pub fn replace(self, args: ReplaceArgs, vm: &VirtualMachine) -> PyResult<PyCode> { |
| 267 | + let posonlyarg_count = match args.co_posonlyargcount { |
| 268 | + OptionalArg::Present(posonlyarg_count) => posonlyarg_count, |
| 269 | + OptionalArg::Missing => self.code.posonlyarg_count, |
| 270 | + }; |
| 271 | + |
| 272 | + let arg_count = match args.co_argcount { |
| 273 | + OptionalArg::Present(arg_count) => arg_count, |
| 274 | + OptionalArg::Missing => self.code.arg_count, |
| 275 | + }; |
| 276 | + |
| 277 | + let source_path = match args.co_filename { |
| 278 | + OptionalArg::Present(source_path) => source_path, |
| 279 | + OptionalArg::Missing => self.code.source_path.to_owned(), |
| 280 | + }; |
| 281 | + |
| 282 | + let first_line_number = match args.co_firstlineno { |
| 283 | + OptionalArg::Present(first_line_number) => first_line_number, |
| 284 | + OptionalArg::Missing => self.code.first_line_number, |
| 285 | + }; |
| 286 | + |
| 287 | + let kwonlyarg_count = match args.co_kwonlyargcount { |
| 288 | + OptionalArg::Present(kwonlyarg_count) => kwonlyarg_count, |
| 289 | + OptionalArg::Missing => self.code.kwonlyarg_count, |
| 290 | + }; |
| 291 | + |
| 292 | + let constants = match args.co_consts { |
| 293 | + OptionalArg::Present(constants) => constants, |
| 294 | + OptionalArg::Missing => self.code.constants.iter().map(|x| x.0.clone()).collect(), |
| 295 | + }; |
| 296 | + |
| 297 | + let obj_name = match args.co_name { |
| 298 | + OptionalArg::Present(obj_name) => obj_name, |
| 299 | + OptionalArg::Missing => self.code.obj_name.to_owned(), |
| 300 | + }; |
| 301 | + |
| 302 | + let names = match args.co_names { |
| 303 | + OptionalArg::Present(names) => names, |
| 304 | + OptionalArg::Missing => self |
| 305 | + .code |
| 306 | + .names |
| 307 | + .deref() |
| 308 | + .iter() |
| 309 | + .map(|name| name.to_pyobject(vm)) |
| 310 | + .collect(), |
| 311 | + }; |
| 312 | + |
| 313 | + let flags = match args.co_flags { |
| 314 | + OptionalArg::Present(flags) => flags, |
| 315 | + OptionalArg::Missing => self.code.flags.bits(), |
| 316 | + }; |
| 317 | + |
| 318 | + let varnames = match args.co_varnames { |
| 319 | + OptionalArg::Present(varnames) => varnames, |
| 320 | + OptionalArg::Missing => self.code.varnames.iter().map(|s| s.to_object()).collect(), |
| 321 | + }; |
| 322 | + |
| 323 | + Ok(PyCode { |
| 324 | + code: CodeObject { |
| 325 | + flags: CodeFlags::from_bits_truncate(flags), |
| 326 | + posonlyarg_count, |
| 327 | + arg_count, |
| 328 | + kwonlyarg_count, |
| 329 | + source_path: source_path.as_object().as_interned_str(vm).unwrap(), |
| 330 | + first_line_number, |
| 331 | + obj_name: obj_name.as_object().as_interned_str(vm).unwrap(), |
| 332 | + |
| 333 | + max_stackdepth: self.code.max_stackdepth, |
| 334 | + instructions: self.code.instructions.clone(), |
| 335 | + locations: self.code.locations.clone(), |
| 336 | + constants: constants.into_iter().map(Literal).collect(), |
| 337 | + names: names |
| 338 | + .into_iter() |
| 339 | + .map(|o| o.as_interned_str(vm).unwrap()) |
| 340 | + .collect(), |
| 341 | + varnames: varnames |
| 342 | + .into_iter() |
| 343 | + .map(|o| o.as_interned_str(vm).unwrap()) |
| 344 | + .collect(), |
| 345 | + cellvars: self.code.cellvars.clone(), |
| 346 | + freevars: self.code.freevars.clone(), |
| 347 | + cell2arg: self.code.cell2arg.clone(), |
| 348 | + }, |
| 349 | + }) |
| 350 | + } |
240 | 351 | } |
241 | 352 |
|
242 | 353 | impl fmt::Display for PyCode { |
|
0 commit comments