Skip to content

Commit b30681a

Browse files
committed
Add basic support for Python functions.
It unexpectedly made me fix unmarshalling of code, which made me merge the two unmarshalling passes.
1 parent 22f3a6e commit b30681a

File tree

17 files changed

+467
-243
lines changed

17 files changed

+467
-243
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "pythonvm"
33
version = "0.1.0"
44
authors = ["Valentin Lorentz <progval+git@progval.net>"]
5+
build = "build.rs"
56

67
[lib]
78
name = "pythonvm"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ A Python virtual machine, written in Rust.
1212

1313
## Try it
1414

15-
1. Install git, [Rust](https://www.rust-lang.org/downloads.html) and [Cargo](https://crates.io/install)
15+
1. Install Python 3.4 (used as a parser and bytecode compiler), git, [Rust](https://www.rust-lang.org/downloads.html) and [Cargo](https://crates.io/install)
1616
2. `git clone https://github.com/ProgVal/pythonvm-rust.git`
1717
3. `cd pythonvm-rust`
18-
4. `cargo run examples/helloworld.pyc`
18+
4. `cargo run pythonlib/ examples/helloworld.pyc`

build.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use std::process::Command;
2+
3+
fn main() {
4+
Command::new("/usr/bin/env")
5+
.arg("python3")
6+
.arg("-m")
7+
.arg("compileall")
8+
.arg("-b") // old-style bytecode layout
9+
.arg("pythonlib/")
10+
.arg("examples/")
11+
.spawn()
12+
.unwrap()
13+
.wait()
14+
.unwrap();
15+
}

examples/helloworld.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print('hello world')

examples/helloworld.pyc

11 Bytes
Binary file not shown.

pythonlib/builtins.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def print(value):
2+
__primitives__.write_stdout(value)
3+
__primitives__.write_stdout("\n")

pythonlib/builtins.pyc

261 Bytes
Binary file not shown.

src/bin.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,32 @@ extern crate pythonvm;
22

33
use std::env::args;
44
use std::fs::File;
5+
use std::path::PathBuf;
56

6-
fn parse_args() -> (String, Option<String>) {
7+
fn parse_args() -> (String, Option<(String, String)>) {
78
let mut args = args();
89
let executable = args.next().unwrap();
10+
let libdir = args.next();
911
let filename = args.next();
1012
let extra = args.next();
11-
match (filename, extra) {
12-
(Some(filename), None) => (executable, Some(filename)),
13+
match (libdir, filename, extra) {
14+
(Some(libdir), Some(filename), None) => (executable, Some((libdir, filename))),
1315
_ => (executable, None),
1416
}
1517
}
1618

1719

1820
pub fn main() {
19-
let filename = match parse_args() {
20-
(_, Some(filename)) => filename,
21+
let (libdir, filename) = match parse_args() {
22+
(_, Some((libdir, filename))) => (libdir, filename),
2123
(executable, None) => {
22-
println!("Syntax: {} filename.pyc", executable);
24+
println!("Syntax: {} pythonlib/ filename.pyc", executable);
2325
return
2426
}
2527
};
2628
let mut file = File::open(filename).unwrap();
27-
let env_proxy = pythonvm::RealEnvProxy::new();
29+
let mut path = PathBuf::new();
30+
path.push(&libdir);
31+
let env_proxy = pythonvm::RealEnvProxy::new(path);
2832
let (_processor, _result) = pythonvm::run_module(&mut file, env_proxy).unwrap();
2933
}

src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ mod objects;
33
mod processor;
44
mod sandbox;
55
mod stack;
6+
mod primitives;
67

78
use std::fmt;
89
use std::io;
910
use processor::Processor;
11+
use std::path::PathBuf;
12+
use std::env;
1013

1114
pub use sandbox::{RealEnvProxy, MockEnvProxy};
1215

@@ -33,15 +36,18 @@ pub fn run_module<R: io::Read, EP: sandbox::EnvProxy>(reader: &mut R, envproxy:
3336
// TODO: do something with the content of the buffer
3437
let mut store = objects::ObjectStore::new();
3538
let module = try!(marshal::read_object(reader, &mut store).map_err(InterpreterError::Unmarshal));
36-
let mut processor = Processor { envproxy: envproxy, store: store, builtin_functions: Processor::get_default_builtins() };
39+
let mut processor = Processor { envproxy: envproxy, store: store, primitives: primitives::get_default_primitives() };
3740
let result = try!(processor.run_code_object(module).map_err(InterpreterError::Processor));
3841
Ok((processor, result))
3942
}
4043

4144
#[test]
42-
fn test_hello_world() {
43-
let mut reader: &[u8] = b"\xee\x0c\r\n\x15j\nW\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\x0b/tmp/foo.py\xda\x08<module>\x01\x00\x00\x00s\x00\x00\x00\x00";
44-
let envproxy = sandbox::MockEnvProxy::new();
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);
4551
let (processor, result) = run_module(&mut reader, envproxy).unwrap();
4652
println!("{:?}", result);
4753
assert_eq!(*processor.envproxy.stdout_content.lock().unwrap(), b"Hello world\n");

0 commit comments

Comments
 (0)