Merge pull request #405 from RustPython/code_object

Code object
This commit is contained in:
Windel Bouwman authored and GitHub committed 2019-02-09 16:20:07 +01:00
commit 95cb0178cd
12 files changed
+149 -62

No files matched your search

Generated
+2
View File
@@ -1,3 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.4"
+4 -4
View File
@@ -68,7 +68,7 @@ fn main() {
handle_exception(&mut vm, result);
}
fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: Option<String>) -> PyResult {
fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> PyResult {
let code_obj = compile::compile(vm, source, &compile::Mode::Exec, source_path)?;
// trace!("Code object: {:?}", code_obj.borrow());
let builtins = vm.get_builtin_scope();
@@ -91,7 +91,7 @@ fn run_command(vm: &mut VirtualMachine, mut source: String) -> PyResult {
// This works around https://github.com/RustPython/RustPython/issues/17
source.push_str("\n");
_run_string(vm, &source, None)
_run_string(vm, &source, "<stdin>".to_string())
}
fn run_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
@@ -105,7 +105,7 @@ fn run_script(vm: &mut VirtualMachine, script_file: &str) -> PyResult {
// Parse an ast from it:
let filepath = Path::new(script_file);
match parser::read_file(filepath) {
Ok(source) => _run_string(vm, &source, Some(filepath.to_str().unwrap().to_string())),
Ok(source) => _run_string(vm, &source, filepath.to_str().unwrap().to_string()),
Err(msg) => {
error!("Parsing went horribly wrong: {}", msg);
std::process::exit(1);
@@ -114,7 +114,7 @@ fn run_script(vm: &mut VirtualMachine, script_file: &str) -> PyResult {
}
fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool {
match compile::compile(vm, source, &compile::Mode::Single, None) {
match compile::compile(vm, source, &compile::Mode::Single, "<stdin>".to_string()) {
Ok(code) => {
match vm.run_code_obj(code, scope) {
Ok(_value) => {
+28
View File
@@ -0,0 +1,28 @@
c1 = compile("1 + 1", "", 'eval')
code_class = type(c1)
def f(x, y, *args, power=1, **kwargs):
assert code_class == type(c1)
z = x * y
return z ** power
c2 = f.__code__
# print(c2)
assert type(c2) == code_class
print(dir(c2))
assert c2.co_argcount == 2
# assert c2.co_cellvars == ()
# assert isinstance(c2.co_code, bytes)
# assert c2.co_consts == (None,)
assert "code.py" in c2.co_filename
assert c2.co_firstlineno == 5, str(c2.co_firstlineno)
# assert isinstance(c2.co_flags, int) # 'OPTIMIZED, NEWLOCALS, NOFREE'
# assert c2.co_freevars == (), str(c2.co_freevars)
assert c2.co_kwonlyargcount == 1, (c2.co_kwonlyargcount)
# assert c2.co_lnotab == 0, c2.co_lnotab # b'\x00\x01' # Line number table
assert c2.co_name == 'f', c2.co_name
# assert c2.co_names == ('code_class', 'type', 'c1', 'AssertionError'), c2.co_names # , c2.co_names
# assert c2.co_nlocals == 4, c2.co_nlocals #
# assert c2.co_stacksize == 2, 'co_stacksize',
# assert c2.co_varnames == ('x', 'y', 'power', 'z'), c2.co_varnames
+3 -3
View File
@@ -150,7 +150,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let filename = objstr::get_value(filename);
compile::compile(vm, &source, &mode, Some(filename))
compile::compile(vm, &source, &mode, filename)
}
fn builtin_delattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -200,7 +200,7 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let source = objstr::get_value(source);
// TODO: fix this newline bug:
let source = format!("{}\n", source);
compile::compile(vm, &source, &mode, None)?
compile::compile(vm, &source, &mode, "<string>".to_string())?
} else {
return Err(vm.new_type_error("code argument must be str or code object".to_string()));
};
@@ -246,7 +246,7 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let source = objstr::get_value(source);
// TODO: fix this newline bug:
let source = format!("{}\n", source);
compile::compile(vm, &source, &mode, None)?
compile::compile(vm, &source, &mode, "<string>".to_string())?
} else if objtype::isinstance(source, &vm.ctx.code_type()) {
source.clone()
} else {
+5 -2
View File
@@ -22,7 +22,8 @@ pub struct CodeObject {
pub varargs: Option<Option<String>>, // *args or *
pub kwonlyarg_names: Vec<String>,
pub varkeywords: Option<Option<String>>, // **kwargs or **
pub source_path: Option<String>,
pub source_path: String,
pub first_line_number: usize,
pub obj_name: String, // Name of the object that created this code object
pub is_generator: bool,
}
@@ -33,7 +34,8 @@ impl CodeObject {
varargs: Option<Option<String>>,
kwonlyarg_names: Vec<String>,
varkeywords: Option<Option<String>>,
source_path: Option<String>,
source_path: String,
first_line_number: usize,
obj_name: String,
) -> CodeObject {
CodeObject {
@@ -45,6 +47,7 @@ impl CodeObject {
kwonlyarg_names,
varkeywords,
source_path,
first_line_number,
obj_name,
is_generator: false,
}
+19 -7
View File
@@ -24,10 +24,10 @@ pub fn compile(
vm: &mut VirtualMachine,
source: &str,
mode: &Mode,
source_path: Option<String>,
source_path: String,
) -> PyResult {
let mut compiler = Compiler::new();
compiler.source_path = source_path.clone();
compiler.source_path = Some(source_path.clone());
compiler.push_new_code_object(source_path, "<module>".to_string());
let syntax_error = vm.context().exceptions.syntax_error.clone();
let result = match mode {
@@ -78,13 +78,15 @@ impl Compiler {
}
}
fn push_new_code_object(&mut self, source_path: Option<String>, obj_name: String) {
fn push_new_code_object(&mut self, source_path: String, obj_name: String) {
let line_number = self.get_source_line_number();
self.code_object_stack.push(CodeObject::new(
Vec::new(),
None,
Vec::new(),
None,
source_path.clone(),
line_number,
obj_name,
));
}
@@ -453,12 +455,14 @@ impl Compiler {
} => {
self.prepare_decorators(decorator_list)?;
self.emit(Instruction::LoadBuildClass);
let line_number = self.get_source_line_number();
self.code_object_stack.push(CodeObject::new(
vec![String::from("__locals__")],
None,
vec![],
None,
self.source_path.clone(),
self.source_path.clone().unwrap(),
line_number,
name.clone(),
));
self.emit(Instruction::LoadName {
@@ -653,12 +657,14 @@ impl Compiler {
});
}
let line_number = self.get_source_line_number();
self.code_object_stack.push(CodeObject::new(
args.args.clone(),
args.vararg.clone(),
args.kwonlyargs.clone(),
args.kwarg.clone(),
self.source_path.clone(),
self.source_path.clone().unwrap(),
line_number,
name.to_string(),
));
@@ -1162,13 +1168,15 @@ impl Compiler {
}
.to_string();
let line_number = self.get_source_line_number();
// Create magnificent function <listcomp>:
self.code_object_stack.push(CodeObject::new(
vec![".0".to_string()],
None,
vec![],
None,
self.source_path.clone(),
self.source_path.clone().unwrap(),
line_number,
name.clone(),
));
@@ -1338,6 +1346,10 @@ impl Compiler {
self.current_source_location = location.clone();
}
fn get_source_line_number(&mut self) -> usize {
self.current_source_location.get_row()
}
fn mark_generator(&mut self) {
self.current_code_object().is_generator = true;
}
@@ -1352,7 +1364,7 @@ mod tests {
use rustpython_parser::parser;
fn compile_exec(source: &str) -> CodeObject {
let mut compiler = Compiler::new();
compiler.push_new_code_object(Option::None, "<module>".to_string());
compiler.push_new_code_object("source_path".to_string(), "<module>".to_string());
let ast = parser::parse_program(&source.to_string()).unwrap();
compiler.compile_program(&ast).unwrap();
compiler.pop_code_object()
+8 -3
View File
@@ -4,8 +4,13 @@ use super::compile;
use super::pyobject::{PyObjectRef, PyResult};
use super::vm::VirtualMachine;
pub fn eval(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> PyResult {
match compile::compile(vm, source, &compile::Mode::Eval, None) {
pub fn eval(
vm: &mut VirtualMachine,
source: &str,
scope: PyObjectRef,
source_path: &str,
) -> PyResult {
match compile::compile(vm, source, &compile::Mode::Eval, source_path.to_string()) {
Ok(bytecode) => {
debug!("Code object: {:?}", bytecode);
vm.run_code_obj(bytecode, scope)
@@ -24,7 +29,7 @@ mod tests {
let source = String::from("print('Hello world')\n");
let mut vm = VirtualMachine::new();
let vars = vm.context().new_scope(None);
let _result = eval(&mut vm, &source, vars);
let _result = eval(&mut vm, &source, vars, "<unittest>");
// TODO: check result?
//assert_eq!(
+10 -20
View File
@@ -70,7 +70,7 @@ impl Frame {
// locals.extend(callargs);
Frame {
code: objcode::copy_code(&code),
code: objcode::get_value(&code),
stack: vec![],
blocks: vec![],
// save the callargs as locals
@@ -88,11 +88,7 @@ impl Frame {
}
pub fn run_frame(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
let filename = if let Some(source_path) = &self.code.source_path {
source_path.to_string()
} else {
"<unknown>".to_string()
};
let filename = &self.code.source_path.to_string();
let prev_frame = mem::replace(&mut vm.current_frame, Some(vm.ctx.new_frame(self.clone())));
@@ -661,13 +657,10 @@ impl Frame {
module: &str,
symbol: &Option<String>,
) -> FrameResult {
let current_path = match &self.code.source_path {
Some(source_path) => {
let mut source_pathbuf = PathBuf::from(source_path);
source_pathbuf.pop();
source_pathbuf
}
None => PathBuf::from("."),
let current_path = {
let mut source_pathbuf = PathBuf::from(&self.code.source_path);
source_pathbuf.pop();
source_pathbuf
};
let obj = import(vm, current_path, module, symbol)?;
@@ -678,13 +671,10 @@ impl Frame {
}
fn import_star(&mut self, vm: &mut VirtualMachine, module: &str) -> FrameResult {
let current_path = match &self.code.source_path {
Some(source_path) => {
let mut source_pathbuf = PathBuf::from(source_path);
source_pathbuf.pop();
source_pathbuf
}
None => PathBuf::from("."),
let current_path = {
let mut source_pathbuf = PathBuf::from(&self.code.source_path);
source_pathbuf.pop();
source_pathbuf
};
// Grab all the names from the module and put them in the context
+1 -1
View File
@@ -35,7 +35,7 @@ fn import_uncached_module(
vm,
&source,
&compile::Mode::Exec,
Some(filepath.to_str().unwrap().to_string()),
filepath.to_str().unwrap().to_string(),
)?;
// trace!("Code object: {:?}", code_obj);
+66 -19
View File
@@ -4,7 +4,7 @@
use super::super::bytecode;
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
@@ -13,15 +13,26 @@ pub fn init(context: &PyContext) {
let code_type = &context.code_type;
context.set_attr(code_type, "__new__", context.new_rustfunc(code_new));
context.set_attr(code_type, "__repr__", context.new_rustfunc(code_repr));
for (name, f) in vec![
(
"co_argcount",
code_co_argcount as fn(&mut VirtualMachine, PyFuncArgs) -> PyResult,
),
("co_filename", code_co_filename),
("co_firstlineno", code_co_firstlineno),
("co_kwonlyargcount", code_co_kwonlyargcount),
("co_name", code_co_name),
] {
context.set_attr(code_type, name, context.new_member_descriptor(f))
}
}
/// Extract rust bytecode object from a python code object.
pub fn copy_code(code_obj: &PyObjectRef) -> bytecode::CodeObject {
let code_obj = code_obj.borrow();
if let PyObjectPayload::Code { ref code } = code_obj.payload {
pub fn get_value(obj: &PyObjectRef) -> bytecode::CodeObject {
if let PyObjectPayload::Code { code } = &obj.borrow().payload {
code.clone()
} else {
panic!("Must be code obj");
panic!("Inner error getting code {:?}", obj)
}
}
@@ -33,18 +44,54 @@ fn code_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
fn code_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(o, Some(vm.ctx.code_type()))]);
// Fetch actual code:
let code = copy_code(o);
let file = if let Some(source_path) = code.source_path {
format!(", file {}", source_path)
} else {
String::new()
};
// TODO: fetch proper line info from code object
let line = ", line 1".to_string();
let repr = format!("<code object at .. {}{}>", file, line);
let code = get_value(o);
let repr = format!(
"<code object {} at 0x{:x} file {:?}, line {}>",
code.obj_name,
o.get_id(),
code.source_path,
code.first_line_number
);
Ok(vm.new_str(repr))
}
fn member_code_obj(
vm: &mut VirtualMachine,
args: PyFuncArgs,
) -> Result<bytecode::CodeObject, PyObjectRef> {
arg_check!(
vm,
args,
required = [
(zelf, Some(vm.ctx.code_type())),
(_cls, Some(vm.ctx.type_type()))
]
);
Ok(get_value(zelf))
}
fn code_co_argcount(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let code_obj = member_code_obj(vm, args)?;
Ok(vm.ctx.new_int(code_obj.arg_names.len()))
}
fn code_co_filename(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let code_obj = member_code_obj(vm, args)?;
let source_path = code_obj.source_path;
Ok(vm.new_str(source_path))
}
fn code_co_firstlineno(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let code_obj = member_code_obj(vm, args)?;
Ok(vm.ctx.new_int(code_obj.first_line_number))
}
fn code_co_kwonlyargcount(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let code_obj = member_code_obj(vm, args)?;
Ok(vm.ctx.new_int(code_obj.kwonlyarg_names.len()))
}
fn code_co_name(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let code_obj = member_code_obj(vm, args)?;
Ok(vm.new_str(code_obj.obj_name))
}
+2 -2
View File
@@ -11,7 +11,7 @@ use std::collections::hash_map::HashMap;
use super::builtins;
use super::bytecode;
use super::frame::Frame;
use super::obj::objcode::copy_code;
use super::obj::objcode;
use super::obj::objgenerator;
use super::obj::objiter;
use super::obj::objsequence;
@@ -282,7 +282,7 @@ impl VirtualMachine {
defaults: &PyObjectRef,
args: PyFuncArgs,
) -> PyResult {
let code_object = copy_code(code);
let code_object = objcode::get_value(code);
let scope = self.ctx.new_scope(Some(scope.clone()));
self.fill_scope_from_args(&code_object, &scope, args, defaults)?;
+1 -1
View File
@@ -123,7 +123,7 @@ fn eval(vm: &mut VirtualMachine, source: &str, vars: PyObjectRef) -> PyResult {
source.push('\n');
}
let code_obj = compile::compile(vm, &source, &compile::Mode::Exec, None)?;
let code_obj = compile::compile(vm, &source, &compile::Mode::Exec, "<string>".to_string())?;
vm.run_code_obj(code_obj, vars)
}