Skip to content

Commit 000f889

Browse files
committed
Add compile builtin
1 parent de29e7f commit 000f889

16 files changed

Lines changed: 207 additions & 175 deletions

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,9 @@ The initial work was based on [windelbouwman/rspython](https://github.com/windel
5151
[rspython]: https://github.com/windelbouwman/rspython
5252
[rustpython]: https://github.com/shinglyu/RustPython
5353
[gitter]: https://gitter.im/rustpython/Lobby
54+
55+
# Links
56+
57+
These are some useful links to related projects:
58+
59+
- https://github.com/ProgVal/pythonvm-rust

src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ fn run_script(script_file: &String) {
4646
let filepath = Path::new(script_file);
4747
match parser::read_file(filepath) {
4848
Ok(source) => {
49-
let bytecode = compile::compile(&source, compile::Mode::Exec).unwrap();
50-
debug!("Code object: {:?}", bytecode);
49+
let code_obj = compile::compile(&mut vm, &source, compile::Mode::Exec).unwrap();
50+
debug!("Code object: {:?}", code_obj);
5151
let vars = vm.new_dict(); // Keep track of local variables
52-
vm.evaluate(bytecode, vars);
52+
vm.run_code_obj(code_obj, vars);
5353
}
5454
Err(msg) => {
5555
error!("Parsing went horribly wrong: {}", msg);

vm/src/builtins.rs

Lines changed: 25 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,11 @@
22
use std::collections::HashMap;
33
use std::io::{self, Write};
44

5+
use super::compile;
56
use super::pyobject::DictProtocol;
67
use super::pyobject::{Executor, PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult};
8+
use super::objbool;
79

8-
/*
9-
* Original impl:
10-
pub fn print(args: Vec<Rc<NativeType>>) -> NativeType {
11-
for elem in args {
12-
// TODO: figure out how python's print vectors
13-
match elem.deref() {
14-
&NativeType::NoneType => println!("None"),
15-
&NativeType::Boolean(ref b)=> {
16-
if *b {
17-
println!("True");
18-
} else {
19-
println!("False");
20-
}
21-
},
22-
&NativeType::Int(ref x) => println!("{}", x),
23-
&NativeType::Float(ref x) => println!("{}", x),
24-
&NativeType::Str(ref x) => println!("{}", x),
25-
&NativeType::Unicode(ref x) => println!("{}", x),
26-
_ => panic!("Print for {:?} not implemented yet", elem),
27-
/*
28-
List(Vec<NativeType>),
29-
Tuple(Vec<NativeType>),
30-
Iter(Vec<NativeType>), // TODO: use Iterator instead
31-
Code(PyCodeObject),
32-
Function(Function),
33-
#[serde(skip_serializing, skip_deserializing)]
34-
NativeFunction(fn(Vec<NativeType>) -> NativeType ),
35-
*/
36-
}
37-
}
38-
NativeType::NoneType
39-
}
40-
*/
4110

4211
fn get_locals(rt: &mut Executor) -> PyObjectRef {
4312
let mut d = rt.new_dict();
@@ -63,7 +32,7 @@ fn dir_object(rt: &mut Executor, obj: PyObjectRef) -> PyObjectRef {
6332
d
6433
}
6534

66-
pub fn dir(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
35+
pub fn builtin_dir(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
6736
if args.is_empty() {
6837
Ok(dir_locals(rt))
6938
} else {
@@ -72,8 +41,7 @@ pub fn dir(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
7241
}
7342
}
7443

75-
pub fn print(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
76-
// println!("Woot: {:?}", args);
44+
pub fn builtin_print(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
7745
trace!("print called with {:?}", args);
7846
for a in args {
7947
print!("{} ", a.borrow().str());
@@ -83,9 +51,18 @@ pub fn print(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
8351
Ok(rt.get_none())
8452
}
8553

86-
pub fn compile(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
87-
// TODO
88-
Ok(rt.new_bool(true))
54+
pub fn builtin_compile(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
55+
if args.len() < 1 {
56+
return Err(rt.new_exception("Expected more arguments".to_string()))
57+
}
58+
// TODO:
59+
let mode = compile::Mode::Eval;
60+
let source = args[0].borrow().str();
61+
62+
match compile::compile(rt, &source, mode) {
63+
Ok(value) => Ok(value),
64+
Err(msg) => Err(rt.new_exception(msg)),
65+
}
8966
}
9067

9168
pub fn locals(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
@@ -111,12 +88,13 @@ pub fn len(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
11188
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
11289
// scope[String::from("print")] = print;
11390
let mut dict = HashMap::new();
114-
dict.insert(String::from("print"), ctx.new_rustfunc(print));
91+
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
11592
dict.insert(String::from("type"), ctx.type_type.clone());
116-
dict.insert(String::from("all"), ctx.new_rustfunc(all));
117-
dict.insert(String::from("any"), ctx.new_rustfunc(any));
118-
dict.insert(String::from("dir"), ctx.new_rustfunc(dir));
93+
dict.insert(String::from("all"), ctx.new_rustfunc(builtin_all));
94+
dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any));
95+
dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir));
11996
dict.insert(String::from("locals"), ctx.new_rustfunc(locals));
97+
dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile));
12098
dict.insert("len".to_string(), ctx.new_rustfunc(len));
12199
let obj = PyObject::new(
122100
PyObjectKind::Module {
@@ -128,12 +106,10 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
128106
obj
129107
}
130108

131-
fn any(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
132-
// TODO
133-
Ok(rt.new_bool(true))
109+
fn builtin_any(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
110+
Ok(rt.new_bool(args.into_iter().any(|e| objbool::boolval(e))))
134111
}
135112

136-
fn all(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
137-
// TODO
138-
Ok(rt.new_bool(true))
113+
fn builtin_all(rt: &mut Executor, args: Vec<PyObjectRef>) -> PyResult {
114+
Ok(rt.new_bool(args.into_iter().all(|e| objbool::boolval(e))))
139115
}

vm/src/compile.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ extern crate rustpython_parser;
66

77
use self::rustpython_parser::{ast, parser};
88
use super::bytecode::{self, CodeObject, Instruction};
9+
use super::pyobject::{Executor, PyObject, PyObjectKind, PyObjectRef};
910

1011
struct Compiler {
1112
code_object_stack: Vec<CodeObject>,
1213
nxt_label: usize,
1314
}
1415

15-
pub fn compile(source: &String, mode: Mode) -> Result<CodeObject, String> {
16+
pub fn compile(rt: &mut Executor, source: &String, mode: Mode) -> Result<PyObjectRef, String> {
1617
let mut compiler = Compiler::new();
1718
compiler.push_code_object(CodeObject::new());
1819
match mode {
1920
Mode::Exec => match parser::parse_program(source) {
2021
Ok(ast) => {
2122
compiler.compile_program(&ast);
22-
Ok(compiler.pop_code_object())
2323
}
24-
Err(msg) => Err(msg),
24+
Err(msg) => return Err(msg),
2525
},
2626
Mode::Eval => match parser::parse_statement(source) {
2727
Ok(statement) => {
@@ -34,11 +34,16 @@ pub fn compile(source: &String, mode: Mode) -> Result<CodeObject, String> {
3434
});
3535
};
3636
compiler.emit(Instruction::ReturnValue);
37-
Ok(compiler.pop_code_object())
3837
}
39-
Err(msg) => Err(msg),
38+
Err(msg) => return Err(msg),
4039
},
41-
}
40+
};
41+
42+
let code = compiler.pop_code_object();
43+
Ok(PyObject::new(
44+
PyObjectKind::Code { code: code },
45+
rt.get_type(),
46+
))
4247
}
4348

4449
pub enum Mode {

vm/src/eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use super::pyobject::{Executor, PyObjectRef, PyResult};
55
use super::vm::VirtualMachine;
66

77
pub fn eval(vm: &mut VirtualMachine, source: &String, locals: PyObjectRef) -> PyResult {
8-
match compile::compile(source, compile::Mode::Eval) {
8+
match compile::compile(vm, source, compile::Mode::Eval) {
99
Ok(bytecode) => {
1010
debug!("Code object: {:?}", bytecode);
11-
vm.evaluate(bytecode, locals)
11+
vm.run_code_obj(bytecode, locals)
1212
}
1313
Err(msg) => {
1414
panic!("Parsing went horribly wrong: {}", msg);

vm/src/frame.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use std::collections::HashMap;
22
use std::fmt;
3-
use std::rc::Rc;
43

54
use super::bytecode;
6-
use super::pyobject::{Executor, PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult};
5+
use super::pyobject::{PyObjectKind, PyObjectRef};
76

87
#[derive(Clone, Debug)]
98
pub enum Block {
@@ -16,7 +15,7 @@ pub enum Block {
1615

1716
pub struct Frame {
1817
// TODO: We are using Option<i32> in stack for handline None return value
19-
pub code: Rc<bytecode::CodeObject>,
18+
pub code: bytecode::CodeObject,
2019
// We need 1 stack per frame
2120
stack: Vec<PyObjectRef>, // The main data frame of the stack machine
2221
blocks: Vec<Block>, // Block frames, for controling loops and exceptions
@@ -26,9 +25,18 @@ pub struct Frame {
2625
// cmp_op: Vec<&'a Fn(NativeType, NativeType) -> bool>, // TODO: change compare to a function list
2726
}
2827

28+
pub fn copy_code(code_obj: PyObjectRef) -> bytecode::CodeObject {
29+
let code_obj = code_obj.borrow();
30+
if let PyObjectKind::Code { ref code } = code_obj.kind {
31+
code.clone()
32+
} else {
33+
panic!("Must be code obj");
34+
}
35+
}
36+
2937
impl Frame {
3038
pub fn new(
31-
code: Rc<bytecode::CodeObject>,
39+
code: PyObjectRef,
3240
callargs: HashMap<String, PyObjectRef>,
3341
globals: PyObjectRef,
3442
) -> Frame {
@@ -44,7 +52,7 @@ impl Frame {
4452
// locals.extend(callargs);
4553

4654
Frame {
47-
code: code,
55+
code: copy_code(code),
4856
stack: vec![],
4957
blocks: vec![],
5058
// save the callargs as locals
@@ -54,6 +62,14 @@ impl Frame {
5462
}
5563
}
5664

65+
pub fn fetch_instruction(&mut self) -> bytecode::Instruction {
66+
// TODO: an immutable reference is enough, we should not
67+
// clone the instruction.
68+
let ins2 = self.code.instructions[self.lasti].clone();
69+
self.lasti += 1;
70+
ins2
71+
}
72+
5773
pub fn push_block(&mut self, block: Block) {
5874
self.blocks.push(block);
5975
}

vm/src/import.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Import mechanics
3+
*/
4+
5+
extern crate rustpython_parser;
6+
7+
use std::path::Path;
8+
9+
use self::rustpython_parser::parser;
10+
use super::compile;
11+
use super::pyobject::{Executor, PyObject, PyObjectKind, PyResult};
12+
13+
pub fn import(rt: &mut Executor, name: &String) -> PyResult {
14+
// Time to search for module in any place:
15+
// TODO: handle 'import sys' as special case?
16+
let filename = format!("{}.py", name);
17+
let filepath = Path::new(&filename);
18+
19+
let source = match parser::read_file(filepath) {
20+
Err(value) => panic!("Error: {}", value),
21+
Ok(value) => value,
22+
};
23+
24+
let code_obj = match compile::compile(rt, &source, compile::Mode::Exec) {
25+
Ok(bytecode) => {
26+
debug!("Code object: {:?}", bytecode);
27+
bytecode
28+
}
29+
Err(value) => {
30+
panic!("Error: {}", value);
31+
}
32+
};
33+
34+
let dict = rt.context().new_dict();
35+
36+
match rt.run_code_obj(code_obj, dict.clone()) {
37+
Ok(value) => {}
38+
Err(value) => return Err(value),
39+
}
40+
41+
let obj = PyObject::new(
42+
PyObjectKind::Module {
43+
name: name.clone(),
44+
dict: dict.clone(),
45+
},
46+
rt.get_type(),
47+
);
48+
Ok(obj)
49+
}

vm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ pub mod bytecode;
1010
pub mod compile;
1111
pub mod eval;
1212
mod frame;
13+
mod import;
1314
mod objdict;
1415
mod objint;
1516
mod objlist;
1617
mod objstr;
1718
mod objtuple;
1819
mod objtype;
20+
mod objbool;
1921
pub mod pyobject;
2022
mod sysmodule;
2123
mod vm;

vm/src/objbool.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
use super::pyobject::{PyObjectKind, PyObjectRef, PyResult};
3+
4+
pub fn boolval(o: PyObjectRef) -> bool {
5+
let obj = o.borrow();
6+
match obj.kind {
7+
PyObjectKind::Boolean { value } => value,
8+
PyObjectKind::Integer { value } => value != 0,
9+
_ => unimplemented!(),
10+
}
11+
}
12+

vm/src/objdict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::pyobject::{Executor, PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult};
1+
use super::pyobject::{Executor, PyObjectRef, PyResult};
22

33
pub fn set_item(rt: &mut Executor, d: PyObjectRef, idx: PyObjectRef, obj: PyObjectRef) -> PyResult {
44
Ok(rt.get_none())

0 commit comments

Comments
 (0)