Merge branch 'master' of https://github.com/RustPython/RustPython into exceptions

This commit is contained in:
Windel Bouwman
2018-08-26 11:40:30 +02:00
12 changed files with 108 additions and 90 deletions

View File

@@ -49,9 +49,9 @@ fn main() {
}
}
fn _run_string(source: &String) {
fn _run_string(source: &String, source_path: Option<String>) {
let mut vm = VirtualMachine::new();
let code_obj = compile::compile(&mut vm, &source, compile::Mode::Exec).unwrap();
let code_obj = compile::compile(&mut vm, &source, compile::Mode::Exec, source_path).unwrap();
debug!("Code object: {:?}", code_obj.borrow());
let builtins = vm.get_builtin_scope();
let vars = vm.context().new_scope(Some(builtins)); // Keep track of local variables
@@ -68,7 +68,7 @@ fn run_command(source: &mut String) {
// This works around https://github.com/RustPython/RustPython/issues/17
source.push_str("\n");
_run_string(source)
_run_string(source, None)
}
fn run_script(script_file: &String) {
@@ -76,7 +76,7 @@ fn run_script(script_file: &String) {
// Parse an ast from it:
let filepath = Path::new(script_file);
match parser::read_file(filepath) {
Ok(source) => _run_string(&source),
Ok(source) => _run_string(&source, Some(filepath.to_str().unwrap().to_string())),
Err(msg) => {
error!("Parsing went horribly wrong: {}", msg);
std::process::exit(1);
@@ -85,7 +85,7 @@ fn run_script(script_file: &String) {
}
fn shell_exec(vm: &mut VirtualMachine, source: &String, scope: PyObjectRef) -> bool {
match compile::compile(vm, source, compile::Mode::Single) {
match compile::compile(vm, source, compile::Mode::Single, None) {
Ok(code) => {
match vm.run_code_obj(code, scope.clone()) {
Ok(_value) => {

View File

@@ -10,6 +10,8 @@ assert not {}
assert not ""
assert not 0.0
assert not None
assert bool() == False
assert bool(1) == True
assert bool({}) == False
@@ -28,3 +30,12 @@ class Falsey:
return False
assert not Falsey()
assert (True or fake)
assert (False or True)
assert not (False or False)
assert ("thing" or 0) == "thing"
assert (True and True)
assert not (False and fake)
assert (True and 5) == 5

View File

@@ -54,7 +54,6 @@ def perform_test(filename, method, test_type):
def run_via_cpython(filename):
""" Simply invoke python itself on the script """
env = os.environ.copy()
env['PYTHONPATH'] = '.'
subprocess.check_call([sys.executable, filename], env=env)
@@ -78,7 +77,6 @@ def run_via_rustpython(filename, test_type):
log_level = 'info' if test_type == _TestType.benchmark else 'trace'
env['RUST_LOG'] = '{},cargo=error,jobserver=error'.format(log_level)
env['RUST_BACKTRACE'] = '1'
env['PYTHONPATH'] = os.path.dirname(filename)
subprocess.check_call(
['cargo', 'run', '--release', filename], env=env)

View File

@@ -102,7 +102,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let mode = compile::Mode::Eval;
let source = args.args[0].borrow().str();
match compile::compile(vm, &source, mode) {
match compile::compile(vm, &source, mode, None) {
Ok(value) => Ok(value),
Err(msg) => Err(vm.new_type_error(msg)),
}

View File

@@ -22,15 +22,17 @@ pub struct CodeObject {
pub label_map: HashMap<Label, usize>,
pub locations: Vec<ast::Location>,
pub arg_names: Vec<String>,
pub source_path: Option<String>,
}
impl CodeObject {
pub fn new(arg_names: Vec<String>) -> CodeObject {
pub fn new(arg_names: Vec<String>, source_path: Option<String>) -> CodeObject {
CodeObject {
instructions: Vec::new(),
label_map: HashMap::new(),
locations: Vec::new(),
arg_names: arg_names,
source_path: source_path,
}
}
}

View File

@@ -19,9 +19,10 @@ pub fn compile(
vm: &mut VirtualMachine,
source: &String,
mode: Mode,
source_path: Option<String>,
) -> Result<PyObjectRef, String> {
let mut compiler = Compiler::new();
compiler.push_new_code_object();
compiler.push_new_code_object(source_path);
match mode {
Mode::Exec => match parser::parse_program(source) {
Ok(ast) => {
@@ -84,8 +85,9 @@ impl Compiler {
}
}
fn push_new_code_object(&mut self) {
self.code_object_stack.push(CodeObject::new(Vec::new()));
fn push_new_code_object(&mut self, source_path: Option<String>) {
self.code_object_stack
.push(CodeObject::new(Vec::new(), source_path.clone()));
}
fn pop_code_object(&mut self) -> CodeObject {
@@ -148,13 +150,15 @@ impl Compiler {
match orelse {
None => {
// Only if:
self.compile_test(test, end_label);
self.compile_expression(test);
self.emit(Instruction::JumpIfFalse { target: end_label });
self.compile_statements(body);
}
Some(statements) => {
// if - else:
let else_label = self.new_label();
self.compile_test(test, else_label);
self.compile_expression(test);
self.emit(Instruction::JumpIfFalse { target: else_label });
self.compile_statements(body);
self.emit(Instruction::Jump { target: end_label });
@@ -180,7 +184,8 @@ impl Compiler {
self.set_label(start_label);
self.compile_test(test, end_label);
self.compile_expression(test);
self.emit(Instruction::JumpIfFalse { target: end_label });
self.compile_statements(body);
self.emit(Instruction::Jump {
target: start_label,
@@ -341,7 +346,8 @@ impl Compiler {
}
ast::Statement::FunctionDef { name, args, body } => {
// Create bytecode for this function:
self.code_object_stack.push(CodeObject::new(args.to_vec()));
self.code_object_stack
.push(CodeObject::new(args.to_vec(), None));
self.compile_statements(body);
// Emit None at end:
@@ -369,7 +375,7 @@ impl Compiler {
ast::Statement::ClassDef { name, body, args } => {
self.emit(Instruction::LoadBuildClass);
self.code_object_stack
.push(CodeObject::new(vec![String::from("__locals__")]));
.push(CodeObject::new(vec![String::from("__locals__")], None));
self.emit(Instruction::LoadName {
name: String::from("__locals__"),
});
@@ -527,31 +533,6 @@ impl Compiler {
self.emit(Instruction::BinaryOperation { op: i });
}
fn compile_test(&mut self, expression: &ast::Expression, not_label: Label) {
// Compile expression for test, and jump to label if false
match expression {
ast::Expression::BoolOp { a, op, b } => match op {
ast::BooleanOperator::And => {
self.compile_test(a, not_label);
self.compile_test(b, not_label);
}
ast::BooleanOperator::Or => {
// TODO: Implement boolean or
// TODO: implement short circuit code by fiddeling with the labels
self.new_label();
self.compile_test(a, not_label);
self.compile_test(b, not_label);
panic!("Not impl");
}
},
_ => {
// If all else fail, fall back to simple checking of boolean value:
self.compile_expression(expression);
self.emit(Instruction::JumpIfFalse { target: not_label });
}
}
}
fn compile_expression(&mut self, expression: &ast::Expression) {
trace!("Compiling {:?}", expression);
match expression {
@@ -563,23 +544,28 @@ impl Compiler {
}
self.emit(Instruction::CallFunction { count: count });
}
ast::Expression::BoolOp { a: _, op: _, b: _ } => {
let not_label = self.new_label();
let end_label = self.new_label();
self.compile_test(expression, not_label);
// Load const True
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Boolean { value: true },
});
self.emit(Instruction::Jump { target: end_label });
self.set_label(not_label);
// Load const False
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Boolean { value: false },
});
self.set_label(end_label);
}
ast::Expression::BoolOp { a, op, b } => match op {
ast::BooleanOperator::And => {
let false_label = self.new_label();
self.compile_expression(a);
self.emit(Instruction::Duplicate);
self.emit(Instruction::JumpIfFalse {
target: false_label,
});
self.emit(Instruction::Pop);
self.compile_expression(b);
self.set_label(false_label);
}
ast::BooleanOperator::Or => {
let true_label = self.new_label();
self.compile_expression(a);
self.emit(Instruction::Duplicate);
self.emit(Instruction::JumpIf { target: true_label });
self.emit(Instruction::Pop);
self.compile_expression(b);
self.set_label(true_label);
}
},
ast::Expression::Binop { a, op, b } => {
self.compile_expression(&*a);
self.compile_expression(&*b);
@@ -694,7 +680,8 @@ impl Compiler {
});
}
ast::Expression::Lambda { args, body } => {
self.code_object_stack.push(CodeObject::new(args.to_vec()));
self.code_object_stack
.push(CodeObject::new(args.to_vec(), None));
self.compile_expression(body);
self.emit(Instruction::ReturnValue);
let code = self.code_object_stack.pop().unwrap();

View File

@@ -5,7 +5,7 @@ use super::pyobject::{PyObjectRef, PyResult};
use super::vm::VirtualMachine;
pub fn eval(vm: &mut VirtualMachine, source: &String, scope: PyObjectRef) -> PyResult {
match compile::compile(vm, source, compile::Mode::Eval) {
match compile::compile(vm, source, compile::Mode::Eval, None) {
Ok(bytecode) => {
debug!("Code object: {:?}", bytecode);
vm.run_code_obj(bytecode, scope)

View File

@@ -28,7 +28,12 @@ fn import_module(vm: &mut VirtualMachine, module: &String) -> PyResult {
let source = parser::read_file(filepath.as_path())
.map_err(|e| vm.new_exception(import_error.clone(), format!("Error: {:?}", e)))?;
let code_obj = match compile::compile(vm, &source, compile::Mode::Exec) {
let code_obj = match compile::compile(
vm,
&source,
compile::Mode::Exec,
Some(filepath.to_str().unwrap().to_string()),
) {
Ok(bytecode) => {
debug!("Code object: {:?}", bytecode);
bytecode
@@ -67,7 +72,7 @@ pub fn import(vm: &mut VirtualMachine, module: &String, symbol: &Option<String>)
fn find_source(vm: &VirtualMachine, name: &String) -> io::Result<PathBuf> {
let sys_path = vm.sys_module.get_item("path").unwrap();
let paths: Vec<PathBuf> = match sys_path.borrow().kind {
let mut paths: Vec<PathBuf> = match sys_path.borrow().kind {
PyObjectKind::List { ref elements } => elements
.iter()
.filter_map(|item| match item.borrow().kind {
@@ -77,6 +82,19 @@ fn find_source(vm: &VirtualMachine, name: &String) -> io::Result<PathBuf> {
_ => panic!("sys.path unexpectedly not a list"),
};
let source_path = &vm.current_frame().code.source_path;
paths.insert(
0,
match source_path {
Some(source_path) => {
let mut source_pathbuf = PathBuf::from(source_path);
source_pathbuf.pop();
source_pathbuf
}
None => PathBuf::from("."),
},
);
let suffixes = [".py", "/__init__.py"];
let mut filepaths = vec![];
for path in paths {

View File

@@ -13,14 +13,18 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
PyObjectKind::Tuple { ref elements } => !elements.is_empty(),
PyObjectKind::Dict { ref elements } => !elements.is_empty(),
PyObjectKind::String { ref value } => !value.is_empty(),
PyObjectKind::None { .. } => false,
_ => {
let f = objtype::get_attribute(vm, obj.clone(), &String::from("__bool__"))?;
match vm.invoke(f, PyFuncArgs::new()) {
Ok(result) => match result.borrow().kind {
PyObjectKind::Boolean { value } => value,
_ => return Err(vm.new_type_error(String::from("TypeError"))),
},
Err(err) => return Err(err),
if let Ok(f) = objtype::get_attribute(vm, obj.clone(), &String::from("__bool__")) {
match vm.invoke(f, PyFuncArgs::new()) {
Ok(result) => match result.borrow().kind {
PyObjectKind::Boolean { value } => value,
_ => return Err(vm.new_type_error(String::from("TypeError"))),
},
Err(err) => return Err(err),
}
} else {
true
}
}
};

View File

@@ -32,7 +32,6 @@ pub fn init(context: &PyContext) {
let ref object = context.object;
object.set_attr("__new__", context.new_rustfunc(new_instance));
object.set_attr("__dict__", context.new_member_descriptor(object_dict));
object.set_attr("__bool__", context.new_rustfunc(object_bool));
}
fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -42,7 +41,3 @@ fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
_ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
}
}
fn object_bool(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
Ok(vm.context().new_bool(true))
}

View File

@@ -8,13 +8,12 @@ use std::env;
use super::pyobject::{DictProtocol, PyContext, PyObjectRef};
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let mut path_list = match env::var_os("PYTHONPATH") {
let path_list = match env::var_os("PYTHONPATH") {
Some(paths) => env::split_paths(&paths)
.map(|path| ctx.new_str(path.to_str().unwrap().to_string()))
.collect(),
None => vec![],
};
path_list.insert(0, ctx.new_str("".to_string()));
let path = ctx.new_list(path_list);
let modules = ctx.new_dict();
let sys_name = "sys".to_string();

View File

@@ -72,7 +72,7 @@ impl VirtualMachine {
}
pub fn new_scope(&mut self) -> PyObjectRef {
let parent_scope = self.current_frame().locals.clone();
let parent_scope = self.current_frame_mut().locals.clone();
self.ctx.new_scope(Some(parent_scope))
}
@@ -134,7 +134,11 @@ impl VirtualMachine {
obj.borrow().str()
}
fn current_frame(&mut self) -> &mut Frame {
pub fn current_frame(&self) -> &Frame {
self.frames.last().unwrap()
}
fn current_frame_mut(&mut self) -> &mut Frame {
self.frames.last_mut().unwrap()
}
@@ -143,15 +147,15 @@ impl VirtualMachine {
}
fn push_block(&mut self, block: Block) {
self.current_frame().push_block(block);
self.current_frame_mut().push_block(block);
}
fn pop_block(&mut self) -> Option<Block> {
self.current_frame().pop_block()
self.current_frame_mut().pop_block()
}
fn last_block(&mut self) -> &Block {
self.current_frame().last_block()
self.current_frame_mut().last_block()
}
fn unwind_loop(&mut self) -> Block {
@@ -183,24 +187,24 @@ impl VirtualMachine {
}
fn push_value(&mut self, obj: PyObjectRef) {
self.current_frame().push_value(obj);
self.current_frame_mut().push_value(obj);
}
fn pop_value(&mut self) -> PyObjectRef {
self.current_frame().pop_value()
self.current_frame_mut().pop_value()
}
fn pop_multiple(&mut self, count: usize) -> Vec<PyObjectRef> {
self.current_frame().pop_multiple(count)
self.current_frame_mut().pop_multiple(count)
}
fn last_value(&mut self) -> PyObjectRef {
self.current_frame().last_value()
self.current_frame_mut().last_value()
}
fn store_name(&mut self, name: &String) -> Option<PyResult> {
let obj = self.pop_value();
self.current_frame().locals.set_item(name, obj);
self.current_frame_mut().locals.set_item(name, obj);
None
}
@@ -549,7 +553,7 @@ impl VirtualMachine {
// Execute a single instruction:
fn execute_instruction(&mut self) -> Option<PyResult> {
let instruction = self.current_frame().fetch_instruction();
let instruction = self.current_frame_mut().fetch_instruction();
{
trace!("=======");
/* TODO:
@@ -874,7 +878,7 @@ impl VirtualMachine {
}
bytecode::Instruction::StoreLocals => {
let locals = self.pop_value();
let ref mut frame = self.current_frame();
let ref mut frame = self.current_frame_mut();
match frame.locals.borrow_mut().kind {
PyObjectKind::Scope { ref mut scope } => {
scope.locals = locals;
@@ -887,7 +891,7 @@ impl VirtualMachine {
}
fn jump(&mut self, label: &bytecode::Label) {
let current_frame = self.current_frame();
let current_frame = self.current_frame_mut();
let target_pc = current_frame.code.label_map[label];
trace!(
"program counter from {:?} to {:?}",