Merge pull request #1785 from RustPython/coolreader18/builtin-input

Implement input()
This commit is contained in:
Noah authored and GitHub committed 2020-03-01 14:34:36 -06:00
commit 57b149ba81
15 files changed
+102 -76

No files matched your search

Generated
+2
View File
@@ -1420,6 +1420,7 @@ dependencies = [
name = "rustpython"
version = "0.1.1"
dependencies = [
"cfg-if",
"clap",
"cpython",
"dirs 2.0.2",
@@ -1539,6 +1540,7 @@ dependencies = [
"rustpython-compiler",
"rustpython-derive",
"rustpython-parser",
"rustyline",
"serde",
"serde_json",
"sha-1",
+1
View File
@@ -27,6 +27,7 @@ rustpython-parser = {path = "parser", version = "0.1.1"}
rustpython-vm = {path = "vm", version = "0.1.1"}
dirs = "2.0"
num-traits = "0.2.8"
cfg-if = "0.1"
flame = { version = "0.2", optional = true }
flamescope = { version = "0.1", optional = true }
+3 -6
View File
@@ -1,9 +1,8 @@
mod readline;
#[cfg(not(target_os = "wasi"))]
mod rustyline_helper;
mod helper;
use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType};
use rustpython_parser::error::ParseErrorType;
use rustpython_vm::readline::{Readline, ReadlineResult};
use rustpython_vm::{
exceptions::{print_exception, PyBaseExceptionRef},
obj::objtype,
@@ -12,8 +11,6 @@ use rustpython_vm::{
VirtualMachine,
};
use readline::{Readline, ReadlineResult};
enum ShellExecResult {
Ok,
PyErr(PyBaseExceptionRef),
@@ -49,7 +46,7 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
crate_version!()
);
let mut repl = Readline::new(vm, scope.clone());
let mut repl = Readline::new(helper::ShellHelper::new(vm, scope.clone()));
let mut full_input = String::new();
// Retrieve a `history_path_str` dependent on the OS
@@ -2,10 +2,6 @@ use rustpython_vm::obj::objstr::PyStringRef;
use rustpython_vm::pyobject::{PyIterable, PyResult, TryFromObject};
use rustpython_vm::scope::{NameProtocol, Scope};
use rustpython_vm::VirtualMachine;
use rustyline::{
completion::Completer, highlight::Highlighter, hint::Hinter, validate::Validator, Context,
Helper,
};
pub struct ShellHelper<'vm> {
vm: &'vm VirtualMachine,
@@ -146,24 +142,32 @@ impl<'vm> ShellHelper<'vm> {
}
}
impl Completer for ShellHelper<'_> {
type Candidate = String;
cfg_if::cfg_if! {
if #[cfg(not(target_os = "wasi"))] {
use rustyline::{
completion::Completer, highlight::Highlighter, hint::Hinter, validate::Validator, Context,
Helper,
};
impl Completer for ShellHelper<'_> {
type Candidate = String;
fn complete(
&self,
line: &str,
pos: usize,
_ctx: &Context,
) -> rustyline::Result<(usize, Vec<String>)> {
Ok(self
.complete_opt(&line[0..pos])
// as far as I can tell, there's no better way to do both completion
// and indentation (or even just indentation)
.unwrap_or_else(|| (line.len(), vec!["\t".to_owned()])))
fn complete(
&self,
line: &str,
pos: usize,
_ctx: &Context,
) -> rustyline::Result<(usize, Vec<String>)> {
Ok(self
.complete_opt(&line[0..pos])
// as far as I can tell, there's no better way to do both completion
// and indentation (or even just indentation)
.unwrap_or_else(|| (line.len(), vec!["\t".to_owned()])))
}
}
impl Hinter for ShellHelper<'_> {}
impl Highlighter for ShellHelper<'_> {}
impl Validator for ShellHelper<'_> {}
impl Helper for ShellHelper<'_> {}
}
}
impl Hinter for ShellHelper<'_> {}
impl Highlighter for ShellHelper<'_> {}
impl Validator for ShellHelper<'_> {}
impl Helper for ShellHelper<'_> {}
+1
View File
@@ -89,6 +89,7 @@ gethostname = "0.2.0"
subprocess = "0.2.2"
num_cpus = "1"
socket2 = { version = "0.3", features = ["unix"] }
rustyline = "6.0"
[target.'cfg(not(any(target_arch = "wasm32", target_os = "redox")))'.dependencies]
dns-lookup = "1.0"
+20 -1
View File
@@ -30,6 +30,7 @@ use crate::pyobject::{
Either, IdProtocol, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
};
use crate::readline::{Readline, ReadlineResult};
use crate::scope::Scope;
use crate::stdlib::ast;
use crate::vm::VirtualMachine;
@@ -345,7 +346,22 @@ fn builtin_id(obj: PyObjectRef) -> usize {
obj.get_id()
}
// builtin_input
fn builtin_input(prompt: OptionalArg<PyStringRef>, vm: &VirtualMachine) -> PyResult<String> {
let prompt = prompt.as_ref().map_or("", |s| s.as_str());
let mut readline = Readline::new(());
match readline.readline(prompt) {
ReadlineResult::Line(s) => Ok(s),
ReadlineResult::EOF => Err(vm.new_exception_empty(vm.ctx.exceptions.eof_error.clone())),
ReadlineResult::Interrupt => {
Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.clone()))
}
ReadlineResult::IO(e) => Err(vm.new_os_error(e.to_string())),
ReadlineResult::EncodingError => {
Err(vm.new_unicode_decode_error("Error decoding readline input".to_owned()))
}
ReadlineResult::Other(e) => Err(vm.new_runtime_error(e.to_string())),
}
}
fn builtin_isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
single_or_tuple_any(
@@ -797,6 +813,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
"hash" => ctx.new_function(builtin_hash),
"hex" => ctx.new_function(builtin_hex),
"id" => ctx.new_function(builtin_id),
"input" => ctx.new_function(builtin_input),
"int" => ctx.int_type(),
"isinstance" => ctx.new_function(builtin_isinstance),
"issubclass" => ctx.new_function(builtin_issubclass),
@@ -866,6 +883,8 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
"NameError" => ctx.exceptions.name_error.clone(),
"UnboundLocalError" => ctx.exceptions.unbound_local_error.clone(),
"OSError" => ctx.exceptions.os_error.clone(),
// OSError alias
"IOError" => ctx.exceptions.os_error.clone(),
"BlockingIOError" => ctx.exceptions.blocking_io_error.clone(),
"ChildProcessError" => ctx.exceptions.child_process_error.clone(),
"ConnectionError" => ctx.exceptions.connection_error.clone(),
+1 -4
View File
@@ -987,10 +987,7 @@ impl Frame {
0 => match vm.current_exception() {
Some(exc) => exc,
None => {
return Err(vm.new_exception_msg(
vm.ctx.exceptions.runtime_error.clone(),
"No active exception to reraise".to_owned(),
))
return Err(vm.new_runtime_error("No active exception to reraise".to_owned()))
}
},
1 | 2 => ExceptionCtor::try_from_object(vm, self.pop_value())?.instantiate(vm)?,
+1
View File
@@ -70,6 +70,7 @@ pub mod obj;
pub mod py_serde;
mod pyhash;
pub mod pyobject;
pub mod readline;
pub mod scope;
mod sequence;
pub mod slots;
+3 -4
View File
@@ -89,10 +89,9 @@ impl PyCoroutine {
vm.frames.borrow_mut().pop();
self.closed.set(true);
match result {
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception_msg(
vm.ctx.exceptions.runtime_error.clone(),
"generator ignored GeneratorExit".to_owned(),
)),
Ok(ExecutionResult::Yield(_)) => {
Err(vm.new_runtime_error("generator ignored GeneratorExit".to_owned()))
}
Err(e) => {
if isinstance(&e, &vm.ctx.exceptions.generator_exit) {
Ok(())
+3 -4
View File
@@ -564,10 +564,9 @@ macro_rules! dict_iterator {
let mut position = self.position.get();
let dict = self.dict.entries.borrow();
if dict.has_changed_size(&self.size) {
return Err(vm.new_exception_msg(
vm.ctx.exceptions.runtime_error.clone(),
"dictionary changed size during iteration".to_owned(),
));
return Err(
vm.new_runtime_error("dictionary changed size during iteration".to_owned())
);
}
match dict.next_entry(&mut position) {
Some((key, value)) => {
+3 -4
View File
@@ -102,10 +102,9 @@ impl PyGenerator {
vm.frames.borrow_mut().pop();
self.closed.set(true);
match result {
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception_msg(
vm.ctx.exceptions.runtime_error.clone(),
"generator ignored GeneratorExit".to_owned(),
)),
Ok(ExecutionResult::Yield(_)) => {
Err(vm.new_runtime_error("generator ignored GeneratorExit".to_owned()))
}
Err(e) => {
if isinstance(&e, &vm.ctx.exceptions.generator_exit) {
Ok(())
+4 -4
View File
@@ -682,10 +682,10 @@ impl<T: PyValue> PyRef<T> {
if obj.payload_is::<T>() {
Ok(Self::new_ref_unchecked(obj))
} else {
Err(vm.new_exception_msg(
vm.ctx.exceptions.runtime_error.clone(),
format!("Unexpected payload for type {:?}", obj.class().name),
))
Err(vm.new_runtime_error(format!(
"Unexpected payload for type {:?}",
obj.class().name
)))
}
}
+28 -23
View File
@@ -1,8 +1,6 @@
use std::io;
use std::path::Path;
use rustpython_vm::{scope::Scope, VirtualMachine};
type OtherError = Box<dyn std::error::Error>;
type OtherResult<T> = Result<T, OtherError>;
@@ -19,13 +17,16 @@ pub enum ReadlineResult {
mod basic_readline {
use super::*;
pub struct BasicReadline<'vm> {
vm: &'vm VirtualMachine,
pub trait Helper {}
impl<T> Helper for T {}
pub struct Readline<H: Helper> {
helper: H,
}
impl<'vm> BasicReadline<'vm> {
pub fn new(vm: &'vm VirtualMachine, _scope: Scope) -> Self {
BasicReadline { vm }
impl<H: Helper> Readline<H> {
pub fn new(helper: H) -> Self {
Readline { helper }
}
pub fn load_history(&mut self, _path: &Path) -> OtherResult<()> {
@@ -60,16 +61,19 @@ mod basic_readline {
}
}
#[cfg(not(target_os = "wasi"))]
#[cfg(not(target_arch = "wasm32"))]
mod rustyline_readline {
use super::{super::rustyline_helper::ShellHelper, *};
use super::*;
pub struct RustylineReadline<'vm> {
repl: rustyline::Editor<ShellHelper<'vm>>,
pub trait Helper: rustyline::Helper {}
impl<T: rustyline::Helper> Helper for T {}
pub struct Readline<H: Helper> {
repl: rustyline::Editor<H>,
}
impl<'vm> RustylineReadline<'vm> {
pub fn new(vm: &'vm VirtualMachine, scope: Scope) -> Self {
impl<H: Helper> Readline<H> {
pub fn new(helper: H) -> Self {
use rustyline::{At, Cmd, CompletionType, Config, Editor, KeyPress, Movement, Word};
let mut repl = Editor::with_config(
Config::builder()
@@ -85,8 +89,8 @@ mod rustyline_readline {
KeyPress::ControlRight,
Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)),
);
repl.set_helper(Some(ShellHelper::new(vm, scope)));
RustylineReadline { repl }
repl.set_helper(Some(helper));
Readline { repl }
}
pub fn load_history(&mut self, path: &Path) -> OtherResult<()> {
@@ -126,17 +130,18 @@ mod rustyline_readline {
}
}
#[cfg(target_os = "wasi")]
type ReadlineInner<'vm> = basic_readline::BasicReadline<'vm>;
#[cfg(target_arch = "wasm32")]
use basic_readline as readline_inner;
#[cfg(not(target_arch = "wasm32"))]
use rustyline_readline as readline_inner;
#[cfg(not(target_os = "wasi"))]
type ReadlineInner<'vm> = rustyline_readline::RustylineReadline<'vm>;
pub use readline_inner::Helper;
pub struct Readline<'vm>(ReadlineInner<'vm>);
pub struct Readline<H: Helper>(readline_inner::Readline<H>);
impl<'vm> Readline<'vm> {
pub fn new(vm: &'vm VirtualMachine, scope: Scope) -> Self {
Readline(ReadlineInner::new(vm, scope))
impl<H: Helper> Readline<H> {
pub fn new(helper: H) -> Self {
Readline(readline_inner::Readline::new(helper))
}
pub fn load_history(&mut self, path: &Path) -> OtherResult<()> {
self.0.load_history(path)
+1 -4
View File
@@ -205,10 +205,7 @@ pub fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyBaseExceptio
let exc_type = vm.ctx.exceptions.unicode_error.clone();
vm.new_exception_msg(exc_type, err.to_string())
}
nix::Error::UnsupportedOperation => {
let exc_type = vm.ctx.exceptions.runtime_error.clone();
vm.new_exception_msg(exc_type, err.to_string())
}
nix::Error::UnsupportedOperation => vm.new_runtime_error(err.to_string()),
nix::Error::Sys(errno) => {
let exc_type = convert_nix_errno(vm, errno);
vm.new_exception_msg(exc_type, err.to_string())
+5
View File
@@ -520,6 +520,11 @@ impl VirtualMachine {
self.new_exception_msg(import_error, msg)
}
pub fn new_runtime_error(&self, msg: String) -> PyBaseExceptionRef {
let runtime_error = self.ctx.exceptions.runtime_error.clone();
self.new_exception_msg(runtime_error, msg)
}
// TODO: #[track_caller] when stabilized
fn _py_panic_failed(&self, exc: &PyBaseExceptionRef, msg: &str) -> ! {
let show_backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |v| &v != "0");