This commit is contained in:
Windel Bouwman
2018-10-16 23:26:47 +02:00
6 changed files with 115 additions and 22 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
__pycache__
**/*.pytest_cache
.*sw*
.repl_history.txt

View File

@@ -11,3 +11,4 @@ env_logger="0.5.10"
clap = "2.31.2"
rustpython_parser = {path = "parser"}
rustpython_vm = {path = "vm"}
rustyline = "2.1.0"

View File

@@ -17,7 +17,7 @@ Or use the interactive shell:
$ cargo run
Welcome to rustpython
>>>>> 2+2
>>> 2+2
4
<!-- Or use pip to install extra modules:

View File

@@ -6,6 +6,7 @@ extern crate env_logger;
extern crate log;
extern crate rustpython_parser;
extern crate rustpython_vm;
extern crate rustyline;
use clap::{App, Arg};
use rustpython_parser::parser;
@@ -14,8 +15,8 @@ use rustpython_vm::print_exception;
use rustpython_vm::pyobject::{PyObjectRef, PyResult};
use rustpython_vm::VirtualMachine;
use rustpython_vm::{compile, import};
use std::io;
use std::io::prelude::*;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::path::Path;
fn main() {
@@ -146,23 +147,30 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
// Read a single line:
let mut input = String::new();
let mut rl = Editor::<()>::new();
// TODO: Store the history in a proper XDG directory
let repl_history_path = ".repl_history.txt";
if rl.load_history(repl_history_path).is_err() {
println!("No previous history.");
}
loop {
// TODO: modules dont support getattr / setattr yet
//let prompt = match vm.get_attribute(vm.sys_module.clone(), "ps1") {
// Ok(value) => objstr::get_value(&value),
// Err(_) => ">>>>> ".to_string(),
//};
print!(">>>>> ");
io::stdout().flush().expect("Could not flush stdout");
match io::stdin().read_line(&mut input) {
Ok(0) => {
break;
}
Ok(_) => {
match rl.readline(">>> ") {
Ok(line) => {
input.push_str(&line);
input.push_str("\n");
debug!("You entered {:?}", input);
if shell_exec(vm, &input, vars.clone()) {
// Line was complete.
rl.add_history_entry(input.as_ref());
input = String::new();
} else {
loop {
@@ -171,16 +179,11 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
// Ok(value) => objstr::get_value(&value),
// Err(_) => "..... ".to_string(),
//};
print!("..... ");
io::stdout().flush().expect("Could not flush stdout");
let mut line = String::new();
match io::stdin().read_line(&mut line) {
Ok(_) => {
line = line
.trim_right_matches(|c| c == '\r' || c == '\n')
.to_string();
match rl.readline("... ") {
Ok(line) => {
if line.len() == 0 {
if shell_exec(vm, &input, vars.clone()) {
rl.add_history_entry(input.as_ref());
input = String::new();
break;
}
@@ -194,9 +197,21 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
}
}
}
Err(msg) => panic!("Error: {:?}", msg),
Err(ReadlineError::Interrupted) => {
// TODO: Raise a real KeyboardInterrupt exception
println!("^C");
break;
}
Err(ReadlineError::Eof) => {
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
};
}
rl.save_history(repl_history_path).unwrap();
Ok(vm.get_none())
}

View File

@@ -0,0 +1,23 @@
assert ord("a") == 97
assert ord("é") == 233
assert ord("🤡") == 129313
try:
ord()
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with no argument"
try:
ord("")
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with an empty string"
try:
ord("ab")
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with more than one character"

View File

@@ -293,9 +293,36 @@ fn builtin_map(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.ctx.new_list(elements))
}
// builtin_max
fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(x, None), (y, None)]);
let order = vm.call_method(x, "__gt__", vec![y.clone()])?;
if objbool::get_value(&order) {
Ok(x.clone())
} else {
Ok(y.clone())
}
}
// builtin_memoryview
// builtin_min
fn builtin_min(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(x, Some(vm.ctx.int_type())), (y, Some(vm.ctx.int_type()))]
);
use std::cmp::Ordering;
let order = x.cmp(y);
match order {
Ordering::Less | Ordering::Equal => Ok(x.clone()),
_ => Ok(y.clone()),
}
}
fn builtin_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
@@ -323,7 +350,27 @@ fn builtin_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
// builtin_object
// builtin_oct
// builtin_open
// builtin_ord
fn builtin_ord(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(string, Some(vm.ctx.str_type()))]);
let string = objstr::get_value(string);
let string_len = string.chars().count();
if string_len > 1 {
return Err(vm.new_type_error(
format!(
"ord() expected a character, but string of length {} found",
string_len
)
.to_string(),
));
}
match string.chars().next() {
Some(character) => Ok(vm.context().new_int(character as i32)),
None => Err(vm.new_type_error(
"ord() could not guess the integer representing this character".to_string(),
)),
}
}
fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
@@ -454,6 +501,12 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
dict.insert(String::from("list"), ctx.list_type());
dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals));
dict.insert(String::from("map"), ctx.new_rustfunc(builtin_map));
dict.insert(String::from("max"), ctx.new_rustfunc(builtin_max));
dict.insert(String::from("min"), ctx.new_rustfunc(builtin_min));
dict.insert(String::from("ord"), ctx.new_rustfunc(builtin_ord));
dict.insert(String::from("next"), ctx.new_rustfunc(builtin_next));
dict.insert(String::from("pow"), ctx.new_rustfunc(builtin_pow));
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));