forked from Rust-related/RustPython
Merge branch 'master' of https://github.com/RustPython/RustPython into exceptions
This commit is contained in:
10
src/main.rs
10
src/main.rs
@@ -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) => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)),
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
30
vm/src/vm.rs
30
vm/src/vm.rs
@@ -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 {:?}",
|
||||
|
||||
Reference in New Issue
Block a user