mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-17 01:51:39 +09:00
Merge branch 'master' into coolreader18/comptime-pycompilation
This commit is contained in:
@@ -2,12 +2,13 @@
|
||||
//!
|
||||
//! Implements functions listed here: https://docs.python.org/3/library/builtins.html
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::char;
|
||||
use std::io::{self, Write};
|
||||
use std::str;
|
||||
|
||||
use num_bigint::Sign;
|
||||
use num_traits::{Signed, Zero};
|
||||
use num_traits::{Signed, ToPrimitive, Zero};
|
||||
|
||||
use crate::compile;
|
||||
use crate::obj::objbool;
|
||||
@@ -684,11 +685,20 @@ fn builtin_repr(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStringRef>
|
||||
fn builtin_reversed(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(obj, None)]);
|
||||
|
||||
// TODO: fallback to using __len__ and __getitem__, if object supports sequence protocol
|
||||
let method = vm.get_method_or_type_error(obj.clone(), "__reversed__", || {
|
||||
format!("argument to reversed() must be a sequence")
|
||||
})?;
|
||||
vm.invoke(method, PyFuncArgs::default())
|
||||
if let Some(reversed_method) = vm.get_method(obj.clone(), "__reversed__") {
|
||||
vm.invoke(reversed_method?, PyFuncArgs::default())
|
||||
} else {
|
||||
vm.get_method_or_type_error(obj.clone(), "__getitem__", || {
|
||||
format!("argument to reversed() must be a sequence")
|
||||
})?;
|
||||
let len = vm.call_method(&obj.clone(), "__len__", PyFuncArgs::default())?;
|
||||
let obj_iterator = objiter::PySequenceIterator {
|
||||
position: Cell::new(objint::get_value(&len).to_isize().unwrap() - 1),
|
||||
obj: obj.clone(),
|
||||
reversed: true,
|
||||
};
|
||||
Ok(obj_iterator.into_ref(vm).into_object())
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_round(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -846,6 +856,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
|
||||
"IndexError" => ctx.exceptions.index_error.clone(),
|
||||
"ImportError" => ctx.exceptions.import_error.clone(),
|
||||
"FileNotFoundError" => ctx.exceptions.file_not_found_error.clone(),
|
||||
"FileExistsError" => ctx.exceptions.file_exists_error.clone(),
|
||||
"StopIteration" => ctx.exceptions.stop_iteration.clone(),
|
||||
"ZeroDivisionError" => ctx.exceptions.zero_division_error.clone(),
|
||||
"KeyError" => ctx.exceptions.key_error.clone(),
|
||||
|
||||
@@ -148,6 +148,7 @@ pub struct ExceptionZoo {
|
||||
pub base_exception_type: PyClassRef,
|
||||
pub exception_type: PyClassRef,
|
||||
pub file_not_found_error: PyClassRef,
|
||||
pub file_exists_error: PyClassRef,
|
||||
pub import_error: PyClassRef,
|
||||
pub index_error: PyClassRef,
|
||||
pub key_error: PyClassRef,
|
||||
@@ -203,6 +204,7 @@ impl ExceptionZoo {
|
||||
let not_implemented_error = create_type("NotImplementedError", &type_type, &runtime_error);
|
||||
let file_not_found_error = create_type("FileNotFoundError", &type_type, &os_error);
|
||||
let permission_error = create_type("PermissionError", &type_type, &os_error);
|
||||
let file_exists_error = create_type("FileExistsError", &type_type, &os_error);
|
||||
|
||||
let warning = create_type("Warning", &type_type, &exception_type);
|
||||
let bytes_warning = create_type("BytesWarning", &type_type, &warning);
|
||||
@@ -224,6 +226,7 @@ impl ExceptionZoo {
|
||||
base_exception_type,
|
||||
exception_type,
|
||||
file_not_found_error,
|
||||
file_exists_error,
|
||||
import_error,
|
||||
index_error,
|
||||
key_error,
|
||||
|
||||
@@ -357,8 +357,8 @@ impl Frame {
|
||||
}
|
||||
bytecode::Instruction::Import {
|
||||
ref name,
|
||||
ref symbol,
|
||||
} => self.import(vm, name, symbol),
|
||||
ref symbols,
|
||||
} => self.import(vm, name, symbols),
|
||||
bytecode::Instruction::ImportStar { ref name } => self.import_star(vm, name),
|
||||
bytecode::Instruction::LoadName {
|
||||
ref name,
|
||||
@@ -907,25 +907,23 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
fn import(&self, vm: &VirtualMachine, module: &str, symbol: &Option<String>) -> FrameResult {
|
||||
let from_list = match symbol {
|
||||
Some(symbol) => vm.ctx.new_tuple(vec![vm.ctx.new_str(symbol.to_string())]),
|
||||
None => vm.ctx.new_tuple(vec![]),
|
||||
};
|
||||
let module = vm.import(module, &from_list)?;
|
||||
fn import(&self, vm: &VirtualMachine, module: &str, symbols: &Vec<String>) -> FrameResult {
|
||||
let from_list = symbols
|
||||
.iter()
|
||||
.map(|symbol| vm.ctx.new_str(symbol.to_string()))
|
||||
.collect();
|
||||
let module = vm.import(module, &vm.ctx.new_tuple(from_list))?;
|
||||
|
||||
// If we're importing a symbol, look it up and use it, otherwise construct a module and return
|
||||
// that
|
||||
let obj = match symbol {
|
||||
Some(symbol) => vm.get_attribute(module, symbol.as_str()).map_err(|_| {
|
||||
let import_error = vm.context().exceptions.import_error.clone();
|
||||
vm.new_exception(import_error, format!("cannot import name '{}'", symbol))
|
||||
}),
|
||||
None => Ok(module),
|
||||
};
|
||||
|
||||
// Push module on stack:
|
||||
self.push_value(obj?);
|
||||
if symbols.is_empty() {
|
||||
self.push_value(module);
|
||||
} else {
|
||||
for symbol in symbols {
|
||||
let obj = vm
|
||||
.get_attribute(module.clone(), symbol.as_str())
|
||||
.map_err(|_| vm.new_import_error(format!("cannot import name '{}'", symbol)));
|
||||
self.push_value(obj?);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ pub fn get_iter(vm: &VirtualMachine, iter_target: &PyObjectRef) -> PyResult {
|
||||
let obj_iterator = PySequenceIterator {
|
||||
position: Cell::new(0),
|
||||
obj: iter_target.clone(),
|
||||
reversed: false,
|
||||
};
|
||||
Ok(obj_iterator.into_ref(vm).into_object())
|
||||
}
|
||||
@@ -80,8 +81,9 @@ pub fn new_stop_iteration(vm: &VirtualMachine) -> PyObjectRef {
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PySequenceIterator {
|
||||
pub position: Cell<usize>,
|
||||
pub position: Cell<isize>,
|
||||
pub obj: PyObjectRef,
|
||||
pub reversed: bool,
|
||||
}
|
||||
|
||||
impl PyValue for PySequenceIterator {
|
||||
@@ -94,17 +96,22 @@ impl PyValue for PySequenceIterator {
|
||||
impl PySequenceIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let number = vm.ctx.new_int(self.position.get());
|
||||
match vm.call_method(&self.obj, "__getitem__", vec![number]) {
|
||||
Ok(val) => {
|
||||
self.position.set(self.position.get() + 1);
|
||||
Ok(val)
|
||||
if self.position.get() >= 0 {
|
||||
let step: isize = if self.reversed { -1 } else { 1 };
|
||||
let number = vm.ctx.new_int(self.position.get());
|
||||
match vm.call_method(&self.obj, "__getitem__", vec![number]) {
|
||||
Ok(val) => {
|
||||
self.position.set(self.position.get() + step);
|
||||
Ok(val)
|
||||
}
|
||||
Err(ref e) if objtype::isinstance(&e, &vm.ctx.exceptions.index_error) => {
|
||||
Err(new_stop_iteration(vm))
|
||||
}
|
||||
// also catches stop_iteration => stop_iteration
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
Err(ref e) if objtype::isinstance(&e, &vm.ctx.exceptions.index_error) => {
|
||||
Err(new_stop_iteration(vm))
|
||||
}
|
||||
// also catches stop_iteration => stop_iteration
|
||||
Err(e) => Err(e),
|
||||
} else {
|
||||
Err(new_stop_iteration(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1149,6 +1149,7 @@ where
|
||||
objiter::PySequenceIterator {
|
||||
position: Cell::new(0),
|
||||
obj: obj.clone(),
|
||||
reversed: false,
|
||||
}
|
||||
.into_ref(vm)
|
||||
.into_object(),
|
||||
|
||||
@@ -21,16 +21,6 @@ use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{BufferProtocol, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
fn compute_c_flag(mode: &str) -> u16 {
|
||||
match mode {
|
||||
"w" => 512,
|
||||
"x" => 512,
|
||||
"a" => 8,
|
||||
"+" => 2,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PyStringIO {
|
||||
data: RefCell<String>,
|
||||
@@ -132,6 +122,21 @@ fn buffered_reader_read(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.ctx.new_bytes(result))
|
||||
}
|
||||
|
||||
fn compute_c_flag(mode: &str) -> u32 {
|
||||
let flags = match mode {
|
||||
"w" => os::FileCreationFlags::O_WRONLY | os::FileCreationFlags::O_CREAT,
|
||||
"x" => {
|
||||
os::FileCreationFlags::O_WRONLY
|
||||
| os::FileCreationFlags::O_CREAT
|
||||
| os::FileCreationFlags::O_EXCL
|
||||
}
|
||||
"a" => os::FileCreationFlags::O_APPEND,
|
||||
"+" => os::FileCreationFlags::O_RDWR,
|
||||
_ => os::FileCreationFlags::O_RDONLY,
|
||||
};
|
||||
flags.bits()
|
||||
}
|
||||
|
||||
fn file_io_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::io::{self, ErrorKind, Read, Write};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{env, fs};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use num_traits::cast::ToPrimitive;
|
||||
|
||||
use crate::function::{IntoPyNativeFunc, PyFuncArgs};
|
||||
@@ -81,15 +82,31 @@ pub fn os_close(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct FileCreationFlags: u32 {
|
||||
// https://elixir.bootlin.com/linux/v4.8/source/include/uapi/asm-generic/fcntl.h
|
||||
const O_RDONLY = 0o0000_0000;
|
||||
const O_WRONLY = 0o0000_0001;
|
||||
const O_RDWR = 0o0000_0002;
|
||||
const O_CREAT = 0o0000_0100;
|
||||
const O_EXCL = 0o0000_0200;
|
||||
const O_APPEND = 0o0000_2000;
|
||||
const O_NONBLOCK = 0o0000_4000;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [
|
||||
(name, Some(vm.ctx.str_type())),
|
||||
(mode, Some(vm.ctx.int_type()))
|
||||
(flags, Some(vm.ctx.int_type()))
|
||||
],
|
||||
optional = [(dir_fd, Some(vm.ctx.int_type()))]
|
||||
optional = [
|
||||
(_mode, Some(vm.ctx.int_type())),
|
||||
(dir_fd, Some(vm.ctx.int_type()))
|
||||
]
|
||||
);
|
||||
|
||||
let name = name.clone().downcast::<PyString>().unwrap();
|
||||
@@ -102,14 +119,32 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
};
|
||||
let fname = &make_path(vm, name, &dir_fd).value;
|
||||
|
||||
let handle = match objint::get_value(mode).to_u16().unwrap() {
|
||||
0 => OpenOptions::new().read(true).open(&fname),
|
||||
1 => OpenOptions::new().write(true).open(&fname),
|
||||
2 => OpenOptions::new().read(true).write(true).open(&fname),
|
||||
512 => OpenOptions::new().write(true).create(true).open(&fname),
|
||||
_ => OpenOptions::new().read(true).open(&fname),
|
||||
let flags = FileCreationFlags::from_bits(objint::get_value(flags).to_u32().unwrap())
|
||||
.ok_or(vm.new_value_error("Unsupported flag".to_string()))?;
|
||||
|
||||
let mut options = &mut OpenOptions::new();
|
||||
|
||||
if flags.contains(FileCreationFlags::O_WRONLY) {
|
||||
options = options.write(true);
|
||||
} else if flags.contains(FileCreationFlags::O_RDWR) {
|
||||
options = options.read(true).write(true);
|
||||
} else {
|
||||
options = options.read(true);
|
||||
}
|
||||
.map_err(|err| match err.kind() {
|
||||
|
||||
if flags.contains(FileCreationFlags::O_APPEND) {
|
||||
options = options.append(true);
|
||||
}
|
||||
|
||||
if flags.contains(FileCreationFlags::O_CREAT) {
|
||||
if flags.contains(FileCreationFlags::O_EXCL) {
|
||||
options = options.create_new(true);
|
||||
} else {
|
||||
options = options.create(true);
|
||||
}
|
||||
}
|
||||
|
||||
let handle = options.open(&fname).map_err(|err| match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
let exc_type = vm.ctx.exceptions.file_not_found_error.clone();
|
||||
vm.new_exception(exc_type, format!("No such file or directory: {}", &fname))
|
||||
@@ -118,6 +153,10 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let exc_type = vm.ctx.exceptions.permission_error.clone();
|
||||
vm.new_exception(exc_type, format!("Permission denied: {}", &fname))
|
||||
}
|
||||
ErrorKind::AlreadyExists => {
|
||||
let exc_type = vm.ctx.exceptions.file_exists_error.clone();
|
||||
vm.new_exception(exc_type, format!("File exists: {}", &fname))
|
||||
}
|
||||
_ => vm.new_value_error("Unhandled file IO error".to_string()),
|
||||
})?;
|
||||
|
||||
@@ -743,12 +782,13 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"getcwd" => ctx.new_rustfunc(os_getcwd),
|
||||
"chdir" => ctx.new_rustfunc(os_chdir),
|
||||
"fspath" => ctx.new_rustfunc(os_fspath),
|
||||
"O_RDONLY" => ctx.new_int(0),
|
||||
"O_WRONLY" => ctx.new_int(1),
|
||||
"O_RDWR" => ctx.new_int(2),
|
||||
"O_NONBLOCK" => ctx.new_int(4),
|
||||
"O_APPEND" => ctx.new_int(8),
|
||||
"O_CREAT" => ctx.new_int(512)
|
||||
"O_RDONLY" => ctx.new_int(FileCreationFlags::O_RDONLY.bits()),
|
||||
"O_WRONLY" => ctx.new_int(FileCreationFlags::O_WRONLY.bits()),
|
||||
"O_RDWR" => ctx.new_int(FileCreationFlags::O_RDWR.bits()),
|
||||
"O_NONBLOCK" => ctx.new_int(FileCreationFlags::O_NONBLOCK.bits()),
|
||||
"O_APPEND" => ctx.new_int(FileCreationFlags::O_APPEND.bits()),
|
||||
"O_EXCL" => ctx.new_int(FileCreationFlags::O_EXCL.bits()),
|
||||
"O_CREAT" => ctx.new_int(FileCreationFlags::O_CREAT.bits())
|
||||
});
|
||||
|
||||
for support in support_funcs {
|
||||
|
||||
Reference in New Issue
Block a user