Files
RustPython/vm/src/vm.rs
2018-08-29 08:58:20 -04:00

970 lines
34 KiB
Rust

/*
* Implement virtual machine to run instructions.
* See also:
* https://github.com/ProgVal/pythonvm-rust/blob/master/src/processor/mod.rs
*/
extern crate rustpython_parser;
use self::rustpython_parser::ast;
use std::cell::RefMut;
use std::collections::hash_map::HashMap;
use std::ops::Deref;
use super::builtins;
use super::bytecode;
use super::frame::{copy_code, Block, Frame};
use super::import::import;
use super::objbool;
use super::objlist;
use super::objobject;
use super::objstr;
use super::objtype;
use super::pyobject::{
AttributeProtocol, DictProtocol, IdProtocol, ParentProtocol, PyContext, PyFuncArgs, PyObject,
PyObjectKind, PyObjectRef, PyResult,
};
use super::sysmodule;
// use objects::objects;
// Objects are live when they are on stack, or referenced by a name (for now)
pub struct VirtualMachine {
frames: Vec<Frame>,
builtins: PyObjectRef,
pub sys_module: PyObjectRef,
pub ctx: PyContext,
}
impl VirtualMachine {
pub fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult {
let frame = Frame::new(code, scope);
self.run_frame(frame)
}
pub fn new_str(&self, s: String) -> PyObjectRef {
self.ctx.new_str(s)
}
pub fn new_bool(&self, b: bool) -> PyObjectRef {
self.ctx.new_bool(b)
}
pub fn new_dict(&self) -> PyObjectRef {
self.ctx.new_dict()
}
pub fn new_exception(&mut self, exc_type: PyObjectRef, msg: String) -> PyObjectRef {
// TODO: maybe there is a clearer way to create an instance:
info!("New exception created: {}", msg);
let args: Vec<PyObjectRef> = Vec::new();
let args = PyFuncArgs { args: args };
// Call function:
let exception = self.invoke(exc_type, args).unwrap();
exception
}
pub fn new_type_error(&mut self, msg: String) -> PyObjectRef {
let type_error = self.context().exceptions.type_error.clone();
self.new_exception(type_error, msg)
}
pub fn new_scope(&mut self) -> PyObjectRef {
let parent_scope = self.current_frame_mut().locals.clone();
self.ctx.new_scope(Some(parent_scope))
}
pub fn get_none(&self) -> PyObjectRef {
self.ctx.none()
}
pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef {
self.ctx.new_bound_method(function, object)
}
pub fn get_type(&self) -> PyObjectRef {
self.ctx.type_type()
}
pub fn get_object(&self) -> PyObjectRef {
self.ctx.object()
}
pub fn get_locals(&self) -> PyObjectRef {
let scope = &self.frames.last().unwrap().locals;
scope.clone()
/*
match (*scope).kind {
PyObjectKind::Scope { scope } => { scope.locals.clone() },
_ => { panic!("Should be scope") },
} // .clone()
*/
}
pub fn context(&self) -> &PyContext {
&self.ctx
}
pub fn new() -> VirtualMachine {
let ctx = PyContext::new();
let builtins = builtins::make_module(&ctx);
let sysmod = sysmodule::mk_module(&ctx);
VirtualMachine {
frames: vec![],
builtins: builtins,
sys_module: sysmod,
ctx: ctx,
}
}
pub fn get_builtin_scope(&mut self) -> PyObjectRef {
let a2 = &*self.builtins.borrow();
match a2.kind {
PyObjectKind::Module { name: _, ref dict } => dict.clone(),
_ => {
panic!("OMG");
}
}
}
// Container of the virtual machine state:
pub fn to_str(&mut self, obj: PyObjectRef) -> String {
obj.borrow().str()
}
pub fn current_frame(&self) -> &Frame {
self.frames.last().unwrap()
}
fn current_frame_mut(&mut self) -> &mut Frame {
self.frames.last_mut().unwrap()
}
fn pop_frame(&mut self) -> Frame {
self.frames.pop().unwrap()
}
fn push_block(&mut self, block: Block) {
self.current_frame_mut().push_block(block);
}
fn pop_block(&mut self) -> Option<Block> {
self.current_frame_mut().pop_block()
}
fn last_block(&self) -> &Block {
self.current_frame().last_block()
}
fn unwind_loop(&mut self) -> Block {
loop {
let block = self.pop_block();
match block {
Some(Block::Loop { start: _, end: __ }) => break block.unwrap(),
Some(Block::TryExcept { .. }) => {}
None => panic!("No block to break / continue"),
}
}
}
fn unwind_exception(&mut self, exc: PyObjectRef) -> Option<PyObjectRef> {
// unwind block stack on exception and find any handlers:
loop {
let block = self.pop_block();
match block {
Some(Block::TryExcept { handler }) => {
self.push_value(exc);
self.jump(&handler);
return None;
}
Some(_) => {}
None => break,
}
}
Some(exc)
}
fn push_value(&mut self, obj: PyObjectRef) {
self.current_frame_mut().push_value(obj);
}
fn pop_value(&mut self) -> PyObjectRef {
self.current_frame_mut().pop_value()
}
fn pop_multiple(&mut self, count: usize) -> Vec<PyObjectRef> {
self.current_frame_mut().pop_multiple(count)
}
fn last_value(&self) -> PyObjectRef {
self.current_frame().last_value()
}
fn store_name(&mut self, name: &String) -> Option<PyResult> {
let obj = self.pop_value();
self.current_frame_mut().locals.set_item(name, obj);
None
}
fn load_name(&mut self, name: &String) -> Option<PyResult> {
// Lookup name in scope and put it onto the stack!
let mut scope = self.current_frame().locals.clone();
loop {
if scope.contains_key(name) {
let obj = scope.get_item(name).unwrap();
self.push_value(obj);
break None;
} else if scope.has_parent() {
scope = scope.get_parent();
} else {
let name_error_type = self.ctx.exceptions.name_error.clone();
let msg = format!("Has not attribute '{}'", name);
let name_error = self.new_exception(name_error_type, msg);
break Some(Err(name_error));
}
}
}
fn run_frame(&mut self, frame: Frame) -> PyResult {
self.frames.push(frame);
let filename = if let Some(source_path) = &self.current_frame().code.source_path {
source_path.to_string()
} else {
"<unknown>".to_string()
};
// Execute until return or exception:
let value = loop {
let lineno = self.get_lineno();
let result = self.execute_instruction();
match result {
None => {}
Some(Ok(value)) => {
break Ok(value);
}
Some(Err(exception)) => {
// unwind block stack on exception and find any handlers.
// Add an entry in the traceback:
assert!(objtype::isinstance(
exception.clone(),
self.ctx.exceptions.base_exception_type.clone()
));
let traceback = self
.get_attribute(exception.clone(), &"__traceback__".to_string())
.unwrap();
trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
let pos = self.ctx.new_tuple(vec![
self.ctx.new_str(filename.clone()),
self.ctx.new_int(lineno.get_row() as i32),
]);
objlist::append(
self,
PyFuncArgs {
args: vec![traceback, pos],
},
).unwrap();
// exception.__trace
match self.unwind_exception(exception) {
None => {}
Some(exception) => {
// TODO: append line number to traceback?
// traceback.append();
break Err(exception);
}
}
}
}
};
self.pop_frame();
value
}
fn subscript(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
// Subscript implementation: a[b]
let a2 = &*a.borrow();
match &a2.kind {
PyObjectKind::String { ref value } => objstr::subscript(self, value, b),
PyObjectKind::List { ref elements } | PyObjectKind::Tuple { ref elements } => {
super::objsequence::get_item(self, &a, elements, b)
}
_ => Err(self.new_type_error(format!(
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
a, b
))),
}
}
fn execute_store_subscript(&mut self) -> Option<PyResult> {
let idx = self.pop_value();
let obj = self.pop_value();
let value = self.pop_value();
let a2 = &mut *obj.borrow_mut();
let result = match &mut a2.kind {
PyObjectKind::List { ref mut elements } => {
objlist::set_item(self, elements, idx, value)
}
_ => Err(self.new_type_error(format!(
"TypeError: __setitem__ assign type {:?} with index {:?} is not supported (yet?)",
obj, idx
))),
};
match result {
Ok(_) => None,
Err(value) => Some(Err(value)),
}
}
fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
// TODO: Fix this correctly, and for all arithmetic operations
Ok(PyObject::new(
a2 - b2,
a2.typ.clone().unwrap_or(self.get_type()),
))
}
fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
Ok(PyObject::new(a2 + b2, self.get_type()))
}
fn _mul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
Ok(PyObject::new(a2 * b2, self.get_type()))
}
fn _div(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
Ok(PyObject::new(a2 / b2, self.get_type()))
}
fn _pow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
match (&a2.kind, &b2.kind) {
(
&PyObjectKind::Integer { value: ref v1 },
&PyObjectKind::Integer { value: ref v2 },
) => Ok(self.ctx.new_int(v1.pow(*v2 as u32))),
(&PyObjectKind::Float { value: ref v1 }, &PyObjectKind::Integer { value: ref v2 }) => {
Ok(self.ctx.new_float(v1.powf(*v2 as f64)))
}
(&PyObjectKind::Integer { value: ref v1 }, &PyObjectKind::Float { value: ref v2 }) => {
Ok(self.ctx.new_float((*v1 as f64).powf(*v2)))
}
(&PyObjectKind::Float { value: ref v1 }, &PyObjectKind::Float { value: ref v2 }) => {
Ok(self.ctx.new_float(v1.powf(*v2)))
}
_ => panic!("Not impl"),
}
}
fn _modulo(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
Ok(PyObject::new(a2 % b2, self.get_type()))
}
fn execute_binop(&mut self, op: &bytecode::BinaryOperator) -> Option<PyResult> {
let b_ref = self.pop_value();
let a_ref = self.pop_value();
// TODO: if the left hand side provides __add__, invoke that function.
//
let result = match op {
&bytecode::BinaryOperator::Subtract => self._sub(a_ref, b_ref),
&bytecode::BinaryOperator::Add => self._add(a_ref, b_ref),
&bytecode::BinaryOperator::Multiply => self._mul(a_ref, b_ref),
&bytecode::BinaryOperator::Power => self._pow(a_ref, b_ref),
&bytecode::BinaryOperator::Divide => self._div(a_ref, b_ref),
&bytecode::BinaryOperator::Subscript => self.subscript(a_ref, b_ref),
&bytecode::BinaryOperator::Modulo => self._modulo(a_ref, b_ref),
_ => panic!("NOT IMPL {:?}", op),
};
match result {
Ok(value) => {
self.push_value(value);
None
}
Err(value) => Some(Err(value)),
}
}
fn execute_unop(&mut self, op: &bytecode::UnaryOperator) -> Option<PyResult> {
let a = self.pop_value();
let result = match op {
&bytecode::UnaryOperator::Minus => {
// TODO:
// self.invoke('__neg__'
match a.borrow().kind {
PyObjectKind::Integer { value: ref value1 } => Ok(self.ctx.new_int(-*value1)),
_ => panic!("Not impl {:?}", a),
}
}
&bytecode::UnaryOperator::Not => match objbool::boolval(self, a) {
Ok(result) => Ok(self.ctx.new_bool(!result)),
Err(err) => Err(err),
},
_ => panic!("Not impl {:?}", op),
};
match result {
Ok(value) => {
self.push_value(value);
None
}
Err(value) => Some(Err(value)),
}
}
fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 == b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 != b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _lt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 < b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _le(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 <= b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _gt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 > b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _ge(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let b2 = &*b.borrow();
let a2 = &*a.borrow();
let result_bool = a2 >= b2;
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn _id(&self, a: PyObjectRef) -> usize {
a.get_id()
}
fn _is(&self, a: PyObjectRef, b: PyObjectRef) -> bool {
// Pointer equal:
a.is(&b)
}
fn _is_not(&self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
let result_bool = !a.is(&b);
let result = self.ctx.new_bool(result_bool);
Ok(result)
}
fn execute_compare(&mut self, op: &bytecode::ComparisonOperator) -> Option<PyResult> {
let b = self.pop_value();
let a = self.pop_value();
let result = match op {
&bytecode::ComparisonOperator::Equal => self._eq(a, b),
&bytecode::ComparisonOperator::NotEqual => self._ne(a, b),
&bytecode::ComparisonOperator::Less => self._lt(a, b),
&bytecode::ComparisonOperator::LessOrEqual => self._le(a, b),
&bytecode::ComparisonOperator::Greater => self._gt(a, b),
&bytecode::ComparisonOperator::GreaterOrEqual => self._ge(a, b),
&bytecode::ComparisonOperator::Is => Ok(self.ctx.new_bool(self._is(a, b))),
&bytecode::ComparisonOperator::IsNot => self._is_not(a, b),
_ => panic!("NOT IMPL {:?}", op),
};
match result {
Ok(value) => {
self.push_value(value);
None
}
Err(value) => Some(Err(value)),
}
}
pub fn invoke(&mut self, func_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
trace!("Invoke: {:?} {:?}", func_ref, args);
match func_ref.borrow().kind {
PyObjectKind::RustFunction { function } => function(self, args),
PyObjectKind::Function {
ref code,
ref scope,
ref defaults,
} => {
let mut scope = self.ctx.new_scope(Some(scope.clone()));
let code_object = copy_code(code.clone());
let nargs = args.args.len();
let nexpected_args = code_object.arg_names.len();
let args = if nargs > nexpected_args {
return Err(self.new_type_error(format!(
"Expected {} arguments (got: {})",
nexpected_args, nargs
)));
} else if nargs < nexpected_args {
// Use defaults if available
let nrequired_defaults = nexpected_args - nargs;
let available_defaults = match defaults.borrow().kind {
PyObjectKind::Tuple { ref elements } => elements.clone(),
PyObjectKind::None => vec![],
_ => panic!("function defaults not tuple or None"),
};
if nrequired_defaults > available_defaults.len() {
return Err(self.new_type_error(format!(
"Expected {}-{} arguments (got: {})",
nexpected_args - available_defaults.len(),
nexpected_args,
nargs
)));
}
let default_args = available_defaults
.clone()
.split_off(available_defaults.len() - nrequired_defaults);
let mut new_args = args.args.clone();
new_args.extend(default_args);
new_args
} else {
// nargs == nexpected_args
args.args
};
for (name, value) in code_object.arg_names.iter().zip(args) {
scope.set_item(name, value);
}
let frame = Frame::new(code.clone(), scope);
self.run_frame(frame)
}
PyObjectKind::Class {
name: _,
dict: _,
mro: _,
} => objtype::call(self, func_ref.clone(), args),
PyObjectKind::BoundMethod {
ref function,
ref object,
} => self.invoke(function.clone(), args.insert(object.clone())),
PyObjectKind::Instance { .. } => objobject::call(self, args.insert(func_ref.clone())),
ref kind => {
unimplemented!("invoke unimplemented for: {:?}", kind);
}
}
}
fn import(&mut self, module: &String, symbol: &Option<String>) -> Option<PyResult> {
let obj = match import(self, module, symbol) {
Ok(value) => value,
Err(value) => return Some(Err(value)),
};
// Push module on stack:
self.push_value(obj);
None
}
pub fn get_attribute(&mut self, obj: PyObjectRef, attr_name: &String) -> PyResult {
objtype::get_attribute(self, obj.clone(), attr_name)
}
fn load_attr(&mut self, attr_name: &String) -> Option<PyResult> {
let parent = self.pop_value();
match self.get_attribute(parent, attr_name) {
Ok(obj) => {
self.push_value(obj);
None
}
Err(err) => Some(Err(err)),
}
}
fn store_attr(&mut self, attr_name: &String) -> Option<PyResult> {
let parent = self.pop_value();
let value = self.pop_value();
parent.set_attr(attr_name, value);
None
}
// Execute a single instruction:
fn execute_instruction(&mut self) -> Option<PyResult> {
let instruction = self.current_frame_mut().fetch_instruction();
{
trace!("=======");
/* TODO:
for frame in self.frames.iter() {
trace!(" {:?}", frame);
}
*/
trace!(" {:?}", self.current_frame());
trace!(" Executing op code: {:?}", instruction);
trace!("=======");
}
match &instruction {
bytecode::Instruction::LoadConst { ref value } => {
let obj = match value {
&bytecode::Constant::Integer { ref value } => self.ctx.new_int(*value),
&bytecode::Constant::Float { ref value } => self.ctx.new_float(*value),
&bytecode::Constant::String { ref value } => self.new_str(value.clone()),
&bytecode::Constant::Boolean { ref value } => self.new_bool(value.clone()),
&bytecode::Constant::Code { ref code } => {
PyObject::new(PyObjectKind::Code { code: code.clone() }, self.get_type())
}
&bytecode::Constant::None => self.ctx.none(),
};
self.push_value(obj);
None
}
bytecode::Instruction::Import {
ref name,
ref symbol,
} => self.import(name, symbol),
bytecode::Instruction::LoadName { ref name } => self.load_name(name),
bytecode::Instruction::StoreName { ref name } => {
// take top of stack and assign in scope:
self.store_name(name)
}
bytecode::Instruction::StoreSubscript => self.execute_store_subscript(),
bytecode::Instruction::Pop => {
// Pop value from stack and ignore.
self.pop_value();
None
}
bytecode::Instruction::Duplicate => {
// Duplicate top of stack
let value = self.pop_value();
self.push_value(value.clone());
self.push_value(value);
None
}
bytecode::Instruction::Rotate { amount } => {
// Shuffles top of stack amount down
if amount < &2 {
panic!("Can only rotate two or more values");
}
let mut values = Vec::new();
// Pop all values from stack:
for _ in 0..*amount {
values.push(self.pop_value());
}
// Push top of stack back first:
self.push_value(values.remove(0));
// Push other value back in order:
values.reverse();
for value in values {
self.push_value(value);
}
None
}
bytecode::Instruction::BuildList { size } => {
let elements = self.pop_multiple(*size);
let list_obj = self.context().new_list(elements);
self.push_value(list_obj);
None
}
bytecode::Instruction::BuildTuple { size } => {
let elements = self.pop_multiple(*size);
let list_obj = self.context().new_tuple(elements);
self.push_value(list_obj);
None
}
bytecode::Instruction::BuildMap { size } => {
let mut elements = HashMap::new();
for _x in 0..*size {
let obj = self.pop_value();
// XXX: Currently, we only support String keys, so we have to unwrap the
// PyObject (and ensure it is a String).
let key_pyobj = self.pop_value();
let key = match key_pyobj.borrow().kind {
PyObjectKind::String { ref value } => value.clone(),
ref kind => unimplemented!(
"Only strings can be used as dict keys, we saw: {:?}",
kind
),
};
elements.insert(key, obj);
}
let map_obj =
PyObject::new(PyObjectKind::Dict { elements: elements }, self.get_type());
self.push_value(map_obj);
None
}
bytecode::Instruction::BuildSlice { size } => {
assert!(*size == 2 || *size == 3);
let elements = self.pop_multiple(*size);
let mut out: Vec<Option<i32>> = elements
.into_iter()
.map(|x| match x.borrow().kind {
PyObjectKind::Integer { value } => Some(value),
PyObjectKind::None => None,
_ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x),
}).collect();
let start = out[0];
let stop = out[1];
let step = if out.len() == 3 { out[2] } else { None };
let obj = PyObject::new(
PyObjectKind::Slice { start, stop, step },
self.ctx.type_type(),
);
self.push_value(obj);
None
}
bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(op),
bytecode::Instruction::LoadAttr { ref name } => self.load_attr(name),
bytecode::Instruction::StoreAttr { ref name } => self.store_attr(name),
bytecode::Instruction::UnaryOperation { ref op } => self.execute_unop(op),
bytecode::Instruction::CompareOperation { ref op } => self.execute_compare(op),
bytecode::Instruction::ReturnValue => {
let value = self.pop_value();
Some(Ok(value))
}
bytecode::Instruction::SetupLoop { start, end } => {
self.push_block(Block::Loop {
start: *start,
end: *end,
});
None
}
bytecode::Instruction::SetupExcept { handler } => {
self.push_block(Block::TryExcept { handler: *handler });
None
}
bytecode::Instruction::PopBlock => {
self.pop_block();
None
}
bytecode::Instruction::GetIter => {
let iterated_obj = self.pop_value();
let iter_obj = PyObject::new(
PyObjectKind::Iterator {
position: 0,
iterated_obj: iterated_obj,
},
self.ctx.type_type(),
);
self.push_value(iter_obj);
None
}
bytecode::Instruction::ForIter => {
// The top of stack contains the iterator, lets push it forward:
let next_obj: Option<PyObjectRef> = {
let top_of_stack = self.last_value();
let mut ref_mut: RefMut<PyObject> = top_of_stack.deref().borrow_mut();
// We require a mutable pyobject here to update the iterator:
let mut iterator = ref_mut; // &mut PyObject = ref_mut.;
// let () = iterator;
iterator.nxt()
};
// Check the next object:
match next_obj {
Some(value) => {
self.push_value(value);
}
None => {
// Pop iterator from stack:
self.pop_value();
// End of for loop
let end_label = if let Block::Loop { start: _, end } = self.last_block() {
*end
} else {
panic!("Wrong block type")
};
self.jump(&end_label);
}
};
None
}
bytecode::Instruction::MakeFunction { flags } => {
let _qualified_name = self.pop_value();
let code_obj = self.pop_value();
let defaults = if flags.contains(bytecode::FunctionOpArg::HAS_DEFAULTS) {
self.pop_value()
} else {
self.get_none()
};
// pop argc arguments
// argument: name, args, globals
let scope = self.current_frame().locals.clone();
let obj = self.ctx.new_function(code_obj, scope, defaults);
self.push_value(obj);
None
}
bytecode::Instruction::CallFunction { count } => {
let args: Vec<PyObjectRef> = self.pop_multiple(*count);
// TODO: kwargs
let args = PyFuncArgs { args: args };
let func_ref = self.pop_value();
// Call function:
let func_result = self.invoke(func_ref, args);
match func_result {
Ok(value) => {
self.push_value(value);
None
}
Err(value) => {
// Ripple exception upwards:
Some(Err(value))
}
}
}
bytecode::Instruction::Jump { target } => {
self.jump(target);
None
}
bytecode::Instruction::JumpIf { target } => {
let obj = self.pop_value();
match objbool::boolval(self, obj) {
Ok(value) => {
if value {
self.jump(target);
}
None
}
Err(value) => Some(Err(value)),
}
}
bytecode::Instruction::JumpIfFalse { target } => {
let obj = self.pop_value();
match objbool::boolval(self, obj) {
Ok(value) => {
if !value {
self.jump(target);
}
None
}
Err(value) => Some(Err(value)),
}
}
bytecode::Instruction::Raise { argc } => {
let exception = match argc {
1 => self.pop_value(),
0 | 2 | 3 => panic!("Not implemented!"),
_ => panic!("Invalid paramter for RAISE_VARARGS, must be between 0 to 3"),
};
if objtype::isinstance(
exception.clone(),
self.context().exceptions.base_exception_type.clone(),
) {
info!("Exception raised: {:?}", exception);
Some(Err(exception))
} else {
let msg = format!(
"Can only raise BaseException derived types, not {:?}",
exception
);
let type_error_type = self.context().exceptions.type_error.clone();
let type_error = self.new_exception(type_error_type, msg);
Some(Err(type_error))
}
}
bytecode::Instruction::Break => {
let block = self.unwind_loop();
if let Block::Loop { start: _, end } = block {
self.jump(&end);
}
None
}
bytecode::Instruction::Pass => {
// Ah, this is nice, just relax!
None
}
bytecode::Instruction::Continue => {
let block = self.unwind_loop();
if let Block::Loop { start, end: _ } = block {
self.jump(&start);
} else {
assert!(false);
}
None
}
bytecode::Instruction::PrintExpr => {
let expr = self.pop_value();
match expr.borrow().kind {
PyObjectKind::None => (),
_ => {
builtins::builtin_print(
self,
PyFuncArgs {
args: vec![expr.clone()],
},
).unwrap();
}
}
None
}
bytecode::Instruction::LoadBuildClass => {
let rustfunc = PyObject::new(
PyObjectKind::RustFunction {
function: builtins::builtin_build_class_,
},
self.ctx.type_type(),
);
self.push_value(rustfunc);
None
}
bytecode::Instruction::StoreLocals => {
let locals = self.pop_value();
let ref mut frame = self.current_frame_mut();
match frame.locals.borrow_mut().kind {
PyObjectKind::Scope { ref mut scope } => {
scope.locals = locals;
}
_ => panic!("We really expect our scope to be a scope!"),
}
None
}
}
}
fn jump(&mut self, label: &bytecode::Label) {
let current_frame = self.current_frame_mut();
let target_pc = current_frame.code.label_map[label];
trace!(
"program counter from {:?} to {:?}",
current_frame.lasti,
target_pc
);
current_frame.lasti = target_pc;
}
fn get_lineno(&self) -> ast::Location {
self.current_frame().get_lineno()
}
}