Merge branch 'master' into coolreader18/comptime-pycompilation

This commit is contained in:
coolreader18
2019-06-16 09:05:34 -05:00
16 changed files with 213 additions and 102 deletions

View File

@@ -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(),

View File

@@ -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,

View File

@@ -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)
}

View File

@@ -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))
}
}

View File

@@ -1149,6 +1149,7 @@ where
objiter::PySequenceIterator {
position: Cell::new(0),
obj: obj.clone(),
reversed: false,
}
.into_ref(vm)
.into_object(),

View File

@@ -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,

View File

@@ -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 {