10000 Clean the code a bit · ocschwar/pythonvm-rust@5f56ab5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5f56ab5

Browse files
committed
Clean the code a bit
1 parent c199ee2 commit 5f56ab5

File tree

10 files changed

+60
-139
lines changed

10 files changed

+60
-139
lines changed

src/bin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ pub fn main() {
2929
let mut path = PathBuf::new();
3030
path.push(&libdir);
3131
let env_proxy = pythonvm::RealEnvProxy::new(path);
32-
let (_processor, _result) = pythonvm::run_module(&mut file, env_proxy).unwrap();
32+
let (_processor, _result) = pythonvm::run_file(&mut file, env_proxy).unwrap();
3333
}

src/lib.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ mod primitives;
77

88
use std::fmt;
99
use std::io;
10-
use processor::Processor;
11-
use std::path::PathBuf;
12-
use std::env;
10+
use processor::{PyResult, Processor};
1311

14-
pub use sandbox::{RealEnvProxy, MockEnvProxy};
12+
pub use sandbox::{EnvProxy, RealEnvProxy, MockEnvProxy};
1513

1614
#[derive(Debug)]
1715
pub enum InterpreterError {
@@ -30,7 +28,7 @@ impl fmt::Display for InterpreterError {
3028
}
3129
}
3230

33-
pub fn run_module<R: io::Read, EP: sandbox::EnvProxy>(reader: &mut R, envproxy: EP) -> Result<(Processor<EP>, objects::ObjectRef), InterpreterError> {
31+
pub fn run_file<R: io::Read, EP: sandbox::EnvProxy>(reader: &mut R, envproxy: EP) -> Result<(Processor<EP>, PyResult), InterpreterError> {
3432
let mut buf = [0; 12];
3533
try!(reader.read_exact(&mut buf).map_err(InterpreterError::Io));
3634
// TODO: do something with the content of the buffer
@@ -41,14 +39,3 @@ pub fn run_module<R: io::Read, EP: sandbox::EnvProxy>(reader: &mut R, envproxy:
4139
Ok((processor, result))
4240
}
4341

44-
#[test]
45-
fn test_primitive_hello_world() {
46-
let mut reader: &[u8] = b"\xee\x0c\r\n\xb0\x92\x0fW\x15\x00\x00\x00\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x0e\x00\x00\x00e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)\x02z\x0bHello worldN)\x01\xda\x05print\xa9\x00r\x02\x00\x00\x00r\x02\x00\x00\x00\xfa\x16examples/helloworld.py\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
47-
let mut path = PathBuf::new();
48-
path.push(env::current_dir().unwrap());
49-
path.push("pythonlib/");
50-
let envproxy = sandbox::MockEnvProxy::new(path);
51-
let (processor, result) = run_module(&mut reader, envproxy).unwrap();
52-
println!("{:?}", result);
53-
assert_eq!(*processor.envproxy.stdout_content.lock().unwrap(), b"Hello world\n");
54-
}

src/marshal/common.rs

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/marshal/decode.rs

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ pub fn read_object<R: io::Read>(reader: &mut R, store: &mut ObjectStore, referen
201201
Ok(references.get(index as usize).unwrap().clone())
202202
},
203203
'c' => { // “code”
204-
let index = references.len();
205204
let allocate_at = if flag {
206205
let obj_ref = store.allocate(ObjectContent::Hole);
207206
references.push(obj_ref.clone());
@@ -210,7 +209,7 @@ pub fn read_object<R: io::Read>(reader: &mut R, store: &mut ObjectStore, referen
210209
else {
211210
None
212211
};
213-
let argcount = try!(read_long(reader)) as usize;
212+
let argcount = try!(read_long(reader));
214213
let kwonlyargcount = try!(read_long(reader));
215214
let nlocals = try!(read_long(reader));
216215
let stacksize = try!(read_long(reader));
@@ -226,7 +225,7 @@ pub fn read_object<R: io::Read>(reader: &mut R, store: &mut ObjectStore, referen
226225
let firstlineno = try!(read_long(reader));
227226
let lnotab = try!(read_object(reader, store, references)); // TODO: decode this
228227
let code = Code {
229-
argcount: argcount,
228+
argcount: argcount as usize,
230229
kwonlyargcount: kwonlyargcount,
231230
nlocals: nlocals,
232231
stacksize: stacksize,
@@ -357,27 +356,6 @@ fn test_recursive_reference() {
357356
fn test_code() {
358357
// >>> def foo(bar):
359358
// ... return bar
360-
// >>> print(',\n'.join('%s: %s' % (x[3:], getattr(foo.__code__, x)) for x in dir(foo.__code__) if x.startswith('co_')))
361-
362-
// >>> marshal.dumps(foo.__code__)
363-
/*
364-
let code = ObjectContent::Code(Box::new(Code {
365-
argcount: 1,
366-
cellvars: ObjectContent::Ref(1),
367-
code: ObjectContent::Bytes(vec![124, 0, 0, 83]),
368-
consts: ObjectContent::Tuple(vec![ObjectContent::None]),
369-
filename: ObjectContent::Ref(2),
370-
firstlineno: 1,
371-
flags: 67,
372-
freevars: ObjectContent::Ref(1),
373-
kwonlyargcount: 0,
374-
lnotab: ObjectContent::Bytes(vec![0, 1]),
375-
name: ObjectContent::Ref(3),
376-
names: ObjectContent::Ref(1),
377-
nlocals: 1,
378-
stacksize: 1,
379-
varnames: ObjectContent::Tuple(vec![ObjectContent::String("bar".to_string())])
380-
}));*/
381359
let mut store = ObjectStore::new();
382360
let obj = get_obj!(store,
383361
b"\xe3\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00C\x00\x00\x00s\x04\x00\x00\x00|\x00\x00S)\x01N\xa9\x00)\x01Z\x03barr\x01\x00\x00\x00r\x01\x00\x00\x00\xfa\x07<stdin>\xda\x03foo\x01\x00\x00\x00s\x02\x00\x00\x00\x00\x01");
@@ -394,9 +372,8 @@ fn test_code() {
394372
}
395373

396374
#[test]
397-
#[ignore]
398375
fn test_module() {
399-
let mut bytes: &[u8] = b"\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x10\x00\x00\x00d\x00\x00d\x01\x00\x84\x00\x00Z\x00\x00d\x02\x00S)\x03c\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x1e\x00\x00\x00t\x00\x00j\x01\x00|\x00\x00\x83\x01\x00\x01t\x00\x00j\x01\x00d\x01\x00\x83\x01\x00\x01d\x00\x00S)\x02N\xda\x01\n)\x02Z\x0e__primitives__Z\x0cwrite_stdout)\x01\xda\x05value\xa9\x00r\x03\x00\x00\x00\xfa\x15pythonlib/builtins.py\xda\x05print\x01\x00\x00\x00s\x04\x00\x00\x00\x00\x01\r\x01r\x05\x00\x00\x00N)\x01r\x05\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x04\x00\x00\x00\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
376+
let bytes: &[u8] = b"\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x10\x00\x00\x00d\x00\x00d\x01\x00\x84\x00\x00Z\x00\x00d\x02\x00S)\x03c\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x1e\x00\x00\x00t\x00\x00j\x01\x00|\x00\x00\x83\x01\x00\x01t\x00\x00j\x01\x00d\x01\x00\x83\x01\x00\x01d\x00\x00S)\x02N\xda\x01\n)\x02Z\x0e__primitives__Z\x0cwrite_stdout)\x01\xda\x05value\xa9\x00r\x03\x00\x00\x00\xfa\x15pythonlib/builtins.py\xda\x05print\x01\x00\x00\x00s\x04\x00\x00\x00\x00\x01\r\x01r\x05\x00\x00\x00N)\x01r\x05\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x04\x00\x00\x00\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
400377
let mut store = ObjectStore::new();
401-
let obj = get_obj!(store, bytes);
378+
get_obj!(store, bytes);
402379
}

src/marshal/mod.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
1-
pub mod common;
21
pub mod decode;
32

43
use std::io;
5-
use super::objects::{Code, ObjectContent, ObjectRef, ObjectStore};
6-
use self::common::Object as MarshalObject;
7-
use self::common::Code as MarshalCode;
4+
use super::objects::{ObjectRef, ObjectStore};
85

96

107
pub fn read_object<R: io::Read>(reader: &mut R, store: &mut ObjectStore) -> Result<ObjectRef, decode::UnmarshalError> {
118
decode::read_object(reader, store, &mut Vec::new())
129
}
13-
14-
#[test]
15-
#[ignore]
16-
fn test_module() {
17-
let mut bytes: &[u8] = b"\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x10\x00\x00\x00d\x00\x00d\x01\x00\x84\x00\x00Z\x00\x00d\x02\x00S)\x03c\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x1e\x00\x00\x00t\x00\x00j\x01\x00|\x00\x00\x83\x01\x00\x01t\x00\x00j\x01\x00d\x01\x00\x83\x01\x00\x01d\x00\x00S)\x02N\xda\x01\n)\x02Z\x0e__primitives__Z\x0cwrite_stdout)\x01\xda\x05value\xa9\x00r\x03\x00\x00\x00\xfa\x15pythonlib/builtins.py\xda\x05print\x01\x00\x00\x00s\x04\x00\x00\x00\x00\x01\r\x01r\x05\x00\x00\x00N)\x01r\x05\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x04\x00\x00\x00\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
18-
let mut store = ObjectStore::new();
19-
let res = read_object(&mut bytes, &mut store).unwrap();
20-
println!("{:?} {:?}", res, store);
21-
}

src/objects/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::collections::HashMap;
22
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
33

44
#[derive(Debug)]

src/primitives/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::collections::HashMap;
22
use std::io::Write;
33
use super::sandbox::EnvProxy;
4-
use super::processor::{Processor, ProcessorError, PyFunction};
5-
use super::objects::{Code, ObjectStore, ObjectRef, ObjectContent};
4+
use super::processor::{Processor, ProcessorError, PyResult, PyFunction};
5+
use super::objects::{ObjectRef, ObjectContent};
66

77
macro_rules! parse_arguments {
88
( $funcname:expr, $store:expr, $args:ident, $( $argname:tt $argexpected:tt : { $($argpattern:pat => $argcode:block,)* } ),* ) => {{
@@ -24,15 +24,15 @@ macro_rules! parse_arguments {
2424
}};
2525
}
2626

27-
fn write_stdout<EP: EnvProxy>(processor: &mut Processor<EP>, args: Vec<ObjectRef>) -> Result<ObjectRef, ProcessorError> {
27+
fn write_stdout<EP: EnvProxy>(processor: &mut Processor<EP>, args: Vec<ObjectRef>) -> Result<PyResult, ProcessorError> {
2828
parse_arguments!("print", processor.store, args,
2929
"value" "a string or an integer": {
3030
ObjectContent::String(ref s) => {
3131
processor.envproxy.stdout().write(s.clone().into_bytes().as_slice()).unwrap(); // TODO: check
3232
},
3333
}
3434
);
35-
Ok(processor.store.allocate(ObjectContent::None))
35+
Ok(PyResult::Return(processor.store.allocate(ObjectContent::None)))
3636
}
3737

3838

src/processor/mod.rs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use super::stack::{Stack, VectorStack};
66
use self::instructions::Instruction;
77
use std::fmt;
88
use std::collections::HashMap;
9-
use std::io::Write;
109
use std::io::Read;
1110
use super::marshal;
1211

@@ -23,7 +22,6 @@ pub enum ProcessorError {
2322
InvalidVarnameIndex,
2423
UnknownPrimitive(String),
2524
UnmarshalError(marshal::decode::UnmarshalError),
26-
Exception(String),
2725
}
2826

2927
impl fmt::Display for ProcessorError {
@@ -32,8 +30,13 @@ impl fmt::Display for ProcessorError {
3230
}
3331
}
3432

33+
#[derive(Debug)]
34+
pub enum PyResult {
35+
Return(ObjectRef),
36+
}
3537

36-
pub type PyFunction<EP> = fn(&mut Processor<EP>, Vec<ObjectRef>) -> Result<ObjectRef, ProcessorError>;
38+
39+
pub type PyFunction<EP> = fn(&mut Processor<EP>, Vec<ObjectRef>) -> Result<PyResult, ProcessorError>;
3740

3841
pub struct Processor<EP: EnvProxy> {
3942
pub envproxy: EP,
@@ -43,6 +46,7 @@ pub struct Processor<EP: EnvProxy> {
4346

4447
impl<EP: EnvProxy> Processor<EP> {
4548

49+
// Load a name from the namespace (only __primitive__ and locals for now)
4650
fn load_name(&mut self, namespace: &mut HashMap<String, ObjectRef>, name: String) -> Result<ObjectRef, ProcessorError> {
4751
if name == "__primitives__" {
4852
Ok(self.store.allocate(ObjectContent::PrimitiveNamespace))
@@ -51,11 +55,12 @@ impl<EP: EnvProxy> Processor<EP> {
5155
Ok(obj_ref.clone())
5256
}
5357
else {
54-
panic!(format!("Cannot load {}: neither a primitive or in namespace.", name))
58+
panic!(format!("Cannot load {}: neither __primitive__ or in namespace.", name))
5559
}
5660
}
5761

58-
fn call_function(&mut self, namespace: &mut HashMap<String, ObjectRef>, func_ref: &ObjectRef, args: Vec<ObjectRef>, kwargs: Vec<ObjectRef>) -> Result<ObjectRef, ProcessorError> {
62+
// Call a primitive / function / code object, with arguments.
63+
fn call_function(&mut self, namespace: &mut HashMap<String, ObjectRef>, func_ref: &ObjectRef, args: Vec<ObjectRef>, kwargs: Vec<ObjectRef>) -> Result<PyResult, ProcessorError> {
5964
// TODO: clone only if necessary
6065
match self.store.deref(func_ref).content.clone() {
6166
ObjectContent::Code(code) => {
@@ -82,11 +87,13 @@ impl<EP: EnvProxy> Processor<EP> {
8287
}
8388
}
8489

85-
fn run_code(&mut self, namespace: &mut HashMap<String, ObjectRef>, code: Code) -> Result<ObjectRef, ProcessorError> {
90+
// Main interpreter loop
91+
// See https://docs.python.org/3/library/dis.html for a description of instructions
92+
fn run_code(&mut self, namespace: &mut HashMap<String, ObjectRef>, code: Code) -> Result<PyResult, ProcessorError> {
8693
let bytecode: Vec<u8> = code.code;
8794
let instructions: Vec<Instruction> = instructions::InstructionDecoder::new(bytecode.iter()).into_iter().collect();
8895
let mut program_counter = 0 as usize;
89-
let mut stack = VectorStack::new();
96+
let mut stack = VectorStack::<ObjectRef>::new();
9097
loop {
9198
let instruction = try!(instructions.get(program_counter).ok_or(ProcessorError::InvalidProgramCounter));
9299
program_counter += 1;
@@ -95,11 +102,11 @@ impl<EP: EnvProxy> Processor<EP> {
95102
try!(stack.pop().ok_or(ProcessorError::StackTooSmall));
96103
()
97104
},
98-
Instruction::ReturnValue => return Ok(try!(stack.pop().ok_or(ProcessorError::StackTooSmall))),
105+
Instruction::ReturnValue => return Ok(PyResult::Return(try!(stack.pop().ok_or(ProcessorError::StackTooSmall)))),
99106
Instruction::StoreName(i) => {
100107
let name = try!(code.names.get(i).ok_or(ProcessorError::InvalidNameIndex)).clone();
101-
let obj = try!(stack.pop().ok_or(ProcessorError::StackTooSmall));
102-
namespace.insert(name, obj);
108+
let obj_ref = try!(stack.pop().ok_or(ProcessorError::StackTooSmall));
109+
namespace.insert(name, obj_ref);
103110
}
104111
Instruction::LoadConst(i) => stack.push(try!(code.consts.get(i).ok_or(ProcessorError::InvalidConstIndex)).clone()),
105112
Instruction::LoadName(i) | Instruction::LoadGlobal(i) => {
@@ -126,8 +133,10 @@ impl<EP: EnvProxy> Processor<EP> {
126133
let kwargs = try!(stack.pop_many(nb_kwargs*2).ok_or(ProcessorError::StackTooSmall));
127134
let args = try!(stack.pop_many(nb_args).ok_or(ProcessorError::StackTooSmall));
128135
let func = try!(stack.pop().ok_or(ProcessorError::StackTooSmall));
129-
let ret_value = self.call_function(namespace, &func, args, kwargs);
130-
stack.push(try!(ret_value))
136+
let ret = try!(self.call_function(namespace, &func, args, kwargs));
137+
match ret {
138+
PyResult::Return(obj_ref) => stack.push(obj_ref),
139+
};
131140
},
132141
Instruction::MakeFunction(0, 0, 0) => {
133142
// TODO: consume default arguments and annotations
@@ -143,24 +152,26 @@ impl<EP: EnvProxy> Processor<EP> {
143152
};
144153
}
145154

146-
pub fn run_module(&mut self, namespace: &mut HashMap<String, ObjectRef>, module_name: String) -> Result<(), ProcessorError> {
155+
/// Load a module from its name and run it.
156+
/// Functions and attributes will be added in the `namespace`.
157+
pub fn run_module(&mut self, namespace: &mut HashMap<String, ObjectRef>, module_name: String) -> Result<PyResult, ProcessorError> {
147158
let mut builtins_bytecode = self.envproxy.open_module(module_name);
148159
let mut buf = [0; 12];
149-
builtins_bytecode.read_exact(&mut buf);
160+
builtins_bytecode.read_exact(&mut buf).unwrap();
150161
let builtins_code = try!(marshal::read_object(&mut builtins_bytecode, &mut self.store).map_err(ProcessorError::UnmarshalError));
151162
let builtins_code = match self.store.deref(&builtins_code).content {
152163
ObjectContent::Code(ref code) => code.clone(),
153164
ref o => return Err(ProcessorError::NotACodeObject(format!("{:?}", o))),
154165
};
155-
try!(self.run_code(namespace, *builtins_code));
156-
Ok(())
166+
self.run_code(namespace, *builtins_code)
157167
}
158168

159-
pub fn run_code_object(&mut self, module: ObjectRef) -> Result<ObjectRef, ProcessorError> {
169+
/// Entry point to run code. Loads builtins in the code's namespace and then run it.
170+
pub fn run_code_object(&mut self, code_object: ObjectRef) -> Result<PyResult, ProcessorError> {
160171
let mut builtins = HashMap::new();
161-
self.run_module(&mut builtins, "builtins".to_string());
172+
try!(self.run_module(&mut builtins, "builtins".to_string()));
162173

163-
let code = match self.store.deref(&module).content {
174+
let code = match self.store.deref(&code_object).content {
164175
ObjectContent::Code(ref code) => code.clone(),
165176
ref o => return Err(ProcessorError::NotACodeObject(format!("{:?}", o))),
166177
};

src/sandbox/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
use std::io;
22
use std::sync::{Arc, Mutex};
3-
use std::collections::HashMap;
43
use std::path::PathBuf;
5-
use std::io::Bytes;
6-
use std::io::Read;
74
use std::fs::File;
85

9-
use super::objects::{ObjectRef, ObjectStore};
10-
116
/// Real environment (I/O, signals, …) or a mock
127
pub trait EnvProxy {
138
type Stdout: io::Write;

tests/test_basic.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
extern crate pythonvm;
2+
3+
use std::path::PathBuf;
4+
use std::env;
5+
use pythonvm::{MockEnvProxy, run_file};
6+
7+
#[test]
8+
fn test_hello_world() {
9+
let mut reader: &[u8] = b"\xee\x0c\r\n\xb0\x92\x0fW\x15\x00\x00\x00\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x0e\x00\x00\x00e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)\x02z\x0bHello worldN)\x01\xda\x05print\xa9\x00r\x02\x00\x00\x00r\x02\x00\x00\x00\xfa\x16examples/helloworld.py\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
10+
let mut path = PathBuf::new();
11+
path.push(env::current_dir().unwrap());
12+
path.push("pythonlib/");
13+
let envproxy = MockEnvProxy::new(path);
14+
let (processor, _result) = run_file(&mut reader, envproxy).unwrap();
15+
assert_eq!(*processor.envproxy.stdout_content.lock().unwrap(), b"Hello world\n");
16+
}

0 commit comments

Comments
 (0)
0