mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #57 from OddBloke/rustfmt
Format the whole project (and add Travis check to avoid regression)
This commit is contained in:
13
.travis.yml
13
.travis.yml
@@ -39,3 +39,16 @@ matrix:
|
||||
env:
|
||||
- TRAVIS_RUST_VERSION=beta
|
||||
script: tests/.travis-runner.sh
|
||||
- name: rustfmt
|
||||
language: rust
|
||||
rust: nightly
|
||||
cache: cargo
|
||||
before_script:
|
||||
- rustup component add rustfmt-preview
|
||||
script:
|
||||
# Code references the generated python.rs, so put something in
|
||||
# place to make `cargo fmt` happy. (We use `echo` rather than
|
||||
# `touch` because rustfmt complains about the empty file touch
|
||||
# creates.)
|
||||
- echo > parser/src/python.rs
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
@@ -119,11 +119,8 @@ impl<'input> Lexer<'input> {
|
||||
Some('\r') => {
|
||||
return;
|
||||
}
|
||||
Some(_) => {
|
||||
}
|
||||
None => {
|
||||
return
|
||||
}
|
||||
Some(_) => {}
|
||||
None => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,12 +147,8 @@ impl<'input> Lexer<'input> {
|
||||
Some('\\') => {
|
||||
string_content.push('\\');
|
||||
}
|
||||
Some('\'') => {
|
||||
string_content.push('\'')
|
||||
}
|
||||
Some('\"') => {
|
||||
string_content.push('\"')
|
||||
}
|
||||
Some('\'') => string_content.push('\''),
|
||||
Some('\"') => string_content.push('\"'),
|
||||
Some('\n') => {
|
||||
// Ignore Unix EOL character
|
||||
}
|
||||
@@ -170,27 +163,17 @@ impl<'input> Lexer<'input> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('a') => {
|
||||
string_content.push('\x07')
|
||||
}
|
||||
Some('b') => {
|
||||
string_content.push('\x08')
|
||||
}
|
||||
Some('f') => {
|
||||
string_content.push('\x0c')
|
||||
}
|
||||
Some('a') => string_content.push('\x07'),
|
||||
Some('b') => string_content.push('\x08'),
|
||||
Some('f') => string_content.push('\x0c'),
|
||||
Some('n') => {
|
||||
string_content.push('\n');
|
||||
}
|
||||
Some('r') => {
|
||||
string_content.push('\r')
|
||||
},
|
||||
Some('r') => string_content.push('\r'),
|
||||
Some('t') => {
|
||||
string_content.push('\t');
|
||||
}
|
||||
Some('v') => {
|
||||
string_content.push('\x0b')
|
||||
}
|
||||
Some('v') => string_content.push('\x0b'),
|
||||
Some(c) => {
|
||||
string_content.push('\\');
|
||||
string_content.push(c);
|
||||
|
||||
@@ -43,8 +43,10 @@ pub fn parse(filename: &Path) -> Result<ast::Program, String> {
|
||||
pub fn parse_program(source: &String) -> Result<ast::Program, String> {
|
||||
let lxr = lexer::Lexer::new(&source);
|
||||
match python::ProgramParser::new().parse(lxr) {
|
||||
Err(lalrpop_util::ParseError::UnrecognizedToken{token: None, expected: _}) =>
|
||||
Err(String::from("Unexpected end of input.")),
|
||||
Err(lalrpop_util::ParseError::UnrecognizedToken {
|
||||
token: None,
|
||||
expected: _,
|
||||
}) => Err(String::from("Unexpected end of input.")),
|
||||
Err(why) => Err(String::from(format!("{:?}", why))),
|
||||
Ok(p) => Ok(p),
|
||||
}
|
||||
@@ -76,12 +78,7 @@ mod tests {
|
||||
fn test_parse_empty() {
|
||||
let parse_ast = parse_program(&String::from("\n"));
|
||||
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
Ok(ast::Program {
|
||||
statements: vec![]
|
||||
})
|
||||
)
|
||||
assert_eq!(parse_ast, Ok(ast::Program { statements: vec![] }))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -91,20 +88,16 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Program {
|
||||
statements: vec![
|
||||
ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![
|
||||
ast::Expression::String {
|
||||
value: String::from("Hello world"),
|
||||
},
|
||||
],
|
||||
},
|
||||
statements: vec![ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![ast::Expression::String {
|
||||
value: String::from("Hello world"),
|
||||
},],
|
||||
},
|
||||
],
|
||||
},],
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -116,21 +109,19 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Program {
|
||||
statements: vec![
|
||||
ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![
|
||||
ast::Expression::String {
|
||||
value: String::from("Hello world"),
|
||||
},
|
||||
ast::Expression::Number { value: 2 },
|
||||
],
|
||||
},
|
||||
statements: vec![ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![
|
||||
ast::Expression::String {
|
||||
value: String::from("Hello world"),
|
||||
},
|
||||
ast::Expression::Number { value: 2 },
|
||||
],
|
||||
},
|
||||
],
|
||||
},],
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -143,26 +134,18 @@ mod tests {
|
||||
parse_ast,
|
||||
ast::Statement::If {
|
||||
test: ast::Expression::Number { value: 1 },
|
||||
body: vec![
|
||||
ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 10 },
|
||||
},
|
||||
],
|
||||
orelse: Some(vec![
|
||||
ast::Statement::If {
|
||||
test: ast::Expression::Number { value: 2 },
|
||||
body: vec![
|
||||
ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 20 },
|
||||
},
|
||||
],
|
||||
orelse: Some(vec![
|
||||
ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 30 },
|
||||
},
|
||||
]),
|
||||
},
|
||||
]),
|
||||
body: vec![ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 10 },
|
||||
},],
|
||||
orelse: Some(vec![ast::Statement::If {
|
||||
test: ast::Expression::Number { value: 2 },
|
||||
body: vec![ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 20 },
|
||||
},],
|
||||
orelse: Some(vec![ast::Statement::Expression {
|
||||
expression: ast::Expression::Number { value: 30 },
|
||||
},]),
|
||||
},]),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -176,17 +159,16 @@ mod tests {
|
||||
Ok(ast::Statement::Expression {
|
||||
expression: ast::Expression::Lambda {
|
||||
args: vec![String::from("x"), String::from("y")],
|
||||
body:
|
||||
Box::new(ast::Expression::Binop {
|
||||
a: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("x"),
|
||||
}),
|
||||
op: ast::Operator::Mult,
|
||||
b: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("y"),
|
||||
})
|
||||
body: Box::new(ast::Expression::Binop {
|
||||
a: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("x"),
|
||||
}),
|
||||
op: ast::Operator::Mult,
|
||||
b: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("y"),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -198,13 +180,11 @@ mod tests {
|
||||
parse_statement(&source),
|
||||
Ok(ast::Statement::ClassDef {
|
||||
name: String::from("Foo"),
|
||||
body: vec![
|
||||
ast::Statement::FunctionDef {
|
||||
name: String::from("__init__"),
|
||||
args: vec![String::from("self")],
|
||||
body: vec![ast::Statement::Pass],
|
||||
}
|
||||
],
|
||||
body: vec![ast::Statement::FunctionDef {
|
||||
name: String::from("__init__"),
|
||||
args: vec![String::from("self")],
|
||||
body: vec![ast::Statement::Pass],
|
||||
}],
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
// Loosely based on token.h from CPython source:
|
||||
#[derive(Debug)]
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Tok {
|
||||
Name { name: String },
|
||||
Number { value: i32 },
|
||||
@@ -21,7 +19,7 @@ pub enum Tok {
|
||||
Star,
|
||||
Slash,
|
||||
Vbar, // '|'
|
||||
Amper, // '&'
|
||||
Amper, // '&'
|
||||
Less,
|
||||
Greater,
|
||||
Equal,
|
||||
@@ -38,18 +36,18 @@ pub enum Tok {
|
||||
LeftShift,
|
||||
RightShift,
|
||||
DoubleStar,
|
||||
DoubleStarEqual, // '**='
|
||||
DoubleStarEqual, // '**='
|
||||
PlusEqual,
|
||||
MinusEqual,
|
||||
StarEqual,
|
||||
SlashEqual,
|
||||
PercentEqual,
|
||||
AmperEqual, // '&='
|
||||
AmperEqual, // '&='
|
||||
VbarEqual,
|
||||
CircumflexEqual, // '^='
|
||||
CircumflexEqual, // '^='
|
||||
LeftShiftEqual,
|
||||
RightShiftEqual,
|
||||
DoubleSlash, // '//'
|
||||
DoubleSlash, // '//'
|
||||
DoubleSlashEqual,
|
||||
At,
|
||||
AtEqual,
|
||||
@@ -57,7 +55,6 @@ pub enum Tok {
|
||||
Ellipsis,
|
||||
|
||||
// Keywords (alphabetically):
|
||||
|
||||
False,
|
||||
None,
|
||||
True,
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -9,8 +9,8 @@ extern crate rustpython_vm;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use rustpython_parser::parser;
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use rustpython_vm::compile;
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
@@ -29,14 +29,12 @@ fn main() {
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Give the verbosity"),
|
||||
)
|
||||
.arg(
|
||||
).arg(
|
||||
Arg::with_name("c")
|
||||
.short("c")
|
||||
.takes_value(true)
|
||||
.help("run the given string as a program"),
|
||||
)
|
||||
.get_matches();
|
||||
).get_matches();
|
||||
|
||||
// Figure out if a -c option was given:
|
||||
if let Some(command) = matches.value_of("c") {
|
||||
@@ -95,7 +93,7 @@ fn shell_exec(vm: &mut VirtualMachine, source: &String, scope: PyObjectRef) -> b
|
||||
}
|
||||
Err(msg) => {
|
||||
println!("Error: {:?}", msg);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(msg) => {
|
||||
@@ -140,6 +138,7 @@ fn run_shell() {
|
||||
let mut vm = VirtualMachine::new();
|
||||
let builtins = vm.get_builtin_scope();
|
||||
let vars = vm.context().new_scope(Some(builtins)); // Keep track of local variables
|
||||
|
||||
// Read a single line:
|
||||
let mut input = String::new();
|
||||
loop {
|
||||
@@ -162,15 +161,11 @@ fn run_shell() {
|
||||
Ok(_) => {
|
||||
shell_exec(&mut vm, &input, vars.clone());
|
||||
}
|
||||
Err(msg) => {
|
||||
panic!("Error: {:?}", msg)
|
||||
}
|
||||
Err(msg) => panic!("Error: {:?}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(msg) => {
|
||||
panic!("Error: {:?}", msg)
|
||||
}
|
||||
Err(msg) => panic!("Error: {:?}", msg),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ use std::collections::HashMap;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use super::compile;
|
||||
use super::pyobject::DictProtocol;
|
||||
use super::pyobject::{PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult, Scope, IdProtocol, PyFuncArgs};
|
||||
use super::vm::VirtualMachine;
|
||||
use super::objbool;
|
||||
|
||||
use super::pyobject::DictProtocol;
|
||||
use super::pyobject::{
|
||||
IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, Scope,
|
||||
};
|
||||
use super::vm::VirtualMachine;
|
||||
|
||||
fn get_locals(vm: &mut VirtualMachine) -> PyObjectRef {
|
||||
let mut d = vm.new_dict();
|
||||
@@ -56,7 +57,7 @@ fn builtin_any(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if args.args.len() < 1 {
|
||||
return Err(vm.new_exception("Expected more arguments".to_string()))
|
||||
return Err(vm.new_exception("Expected more arguments".to_string()));
|
||||
}
|
||||
// TODO:
|
||||
let mode = compile::Mode::Eval;
|
||||
@@ -93,24 +94,27 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let args = args.args;
|
||||
if args.len() > 3 {
|
||||
return Err(vm.new_exception("Expected at maximum of 3 arguments".to_string()))
|
||||
return Err(vm.new_exception("Expected at maximum of 3 arguments".to_string()));
|
||||
} else if args.len() > 2 {
|
||||
// TODO: handle optional global and locals
|
||||
} else {
|
||||
return Err(vm.new_exception("Expected at least one argument".to_string()))
|
||||
return Err(vm.new_exception("Expected at least one argument".to_string()));
|
||||
}
|
||||
let source = args[0].clone();
|
||||
let _globals = args[1].clone();
|
||||
let locals = args[2].clone();
|
||||
|
||||
let code_obj = source; // if source.borrow().kind
|
||||
let code_obj = source; // if source.borrow().kind
|
||||
|
||||
// Construct new scope:
|
||||
let scope_inner = Scope {
|
||||
locals: locals,
|
||||
parent: None,
|
||||
};
|
||||
let scope = PyObject { kind: PyObjectKind::Scope { scope: scope_inner }, typ: None }.into_ref();
|
||||
let scope = PyObject {
|
||||
kind: PyObjectKind::Scope { scope: scope_inner },
|
||||
typ: None,
|
||||
}.into_ref();
|
||||
|
||||
// Run the source:
|
||||
vm.run_code_obj(code_obj, scope)
|
||||
@@ -130,7 +134,7 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
fn builtin_id(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if args.args.len() != 1 {
|
||||
return Err(vm.new_exception("Expected only one argument".to_string()))
|
||||
return Err(vm.new_exception("Expected only one argument".to_string()));
|
||||
}
|
||||
|
||||
Ok(vm.context().new_int(args.args[0].get_id() as i32))
|
||||
@@ -152,7 +156,8 @@ fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
PyObjectKind::Tuple { ref elements } => elements.len(),
|
||||
PyObjectKind::String { ref value } => value.len(),
|
||||
_ => {
|
||||
return Err(vm.context()
|
||||
return Err(vm
|
||||
.context()
|
||||
.new_str("TypeError: object of this type has no len()".to_string()))
|
||||
}
|
||||
};
|
||||
@@ -226,9 +231,10 @@ fn builtin_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args.args[0].borrow().str()
|
||||
}
|
||||
_ => {
|
||||
return Err(vm.context()
|
||||
.new_str("TypeError: object of this type cannot be converted to str".to_string()))
|
||||
},
|
||||
return Err(vm
|
||||
.context()
|
||||
.new_str("TypeError: object of this type cannot be converted to str".to_string()))
|
||||
}
|
||||
};
|
||||
Ok(vm.new_str(s))
|
||||
}
|
||||
@@ -261,7 +267,15 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
|
||||
dict.insert(String::from("tuple"), ctx.tuple_type.clone());
|
||||
dict.insert(String::from("type"), ctx.type_type.clone());
|
||||
let d2 = PyObject::new(PyObjectKind::Dict { elements: dict }, ctx.type_type.clone());
|
||||
let scope = PyObject::new(PyObjectKind::Scope { scope: Scope { locals: d2, parent: None} }, ctx.type_type.clone());
|
||||
let scope = PyObject::new(
|
||||
PyObjectKind::Scope {
|
||||
scope: Scope {
|
||||
locals: d2,
|
||||
parent: None,
|
||||
},
|
||||
},
|
||||
ctx.type_type.clone(),
|
||||
);
|
||||
let obj = PyObject::new(
|
||||
PyObjectKind::Module {
|
||||
name: "__builtins__".to_string(),
|
||||
@@ -281,6 +295,11 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResu
|
||||
};
|
||||
|
||||
let new_dict = vm.new_dict();
|
||||
&vm.invoke(function, PyFuncArgs { args: vec![ new_dict.clone() ] });
|
||||
&vm.invoke(
|
||||
function,
|
||||
PyFuncArgs {
|
||||
args: vec![new_dict.clone()],
|
||||
},
|
||||
);
|
||||
Ok(vm.new_class(name.to_string(), new_dict))
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct CodeObject {
|
||||
}
|
||||
|
||||
impl CodeObject {
|
||||
pub fn new(arg_names : Vec<String>) -> CodeObject {
|
||||
pub fn new(arg_names: Vec<String>) -> CodeObject {
|
||||
CodeObject {
|
||||
instructions: Vec::new(),
|
||||
label_map: HashMap::new(),
|
||||
@@ -38,35 +38,72 @@ pub enum Instruction {
|
||||
name: String,
|
||||
symbol: Option<String>,
|
||||
},
|
||||
LoadName { name: String },
|
||||
StoreName { name: String },
|
||||
LoadName {
|
||||
name: String,
|
||||
},
|
||||
StoreName {
|
||||
name: String,
|
||||
},
|
||||
StoreSubscript,
|
||||
StoreAttr { name: String },
|
||||
LoadConst { value: Constant },
|
||||
UnaryOperation { op: UnaryOperator },
|
||||
BinaryOperation { op: BinaryOperator },
|
||||
LoadAttr { name: String },
|
||||
CompareOperation { op: ComparisonOperator },
|
||||
StoreAttr {
|
||||
name: String,
|
||||
},
|
||||
LoadConst {
|
||||
value: Constant,
|
||||
},
|
||||
UnaryOperation {
|
||||
op: UnaryOperator,
|
||||
},
|
||||
BinaryOperation {
|
||||
op: BinaryOperator,
|
||||
},
|
||||
LoadAttr {
|
||||
name: String,
|
||||
},
|
||||
CompareOperation {
|
||||
op: ComparisonOperator,
|
||||
},
|
||||
Pop,
|
||||
Rotate { amount: usize },
|
||||
Rotate {
|
||||
amount: usize,
|
||||
},
|
||||
Duplicate,
|
||||
GetIter,
|
||||
Pass,
|
||||
Continue,
|
||||
Break,
|
||||
Jump { target: Label },
|
||||
JumpIf { target: Label },
|
||||
Jump {
|
||||
target: Label,
|
||||
},
|
||||
JumpIf {
|
||||
target: Label,
|
||||
},
|
||||
MakeFunction,
|
||||
CallFunction { count: usize },
|
||||
CallFunction {
|
||||
count: usize,
|
||||
},
|
||||
ForIter,
|
||||
ReturnValue,
|
||||
SetupLoop { start: Label, end: Label },
|
||||
SetupLoop {
|
||||
start: Label,
|
||||
end: Label,
|
||||
},
|
||||
PopBlock,
|
||||
Raise { argc: usize },
|
||||
BuildTuple { size: usize },
|
||||
BuildList { size: usize },
|
||||
BuildMap { size: usize },
|
||||
BuildSlice { size: usize },
|
||||
Raise {
|
||||
argc: usize,
|
||||
},
|
||||
BuildTuple {
|
||||
size: usize,
|
||||
},
|
||||
BuildList {
|
||||
size: usize,
|
||||
},
|
||||
BuildMap {
|
||||
size: usize,
|
||||
},
|
||||
BuildSlice {
|
||||
size: usize,
|
||||
},
|
||||
PrintExpr,
|
||||
LoadBuildClass,
|
||||
StoreLocals,
|
||||
@@ -132,7 +169,8 @@ pub enum BlockType {
|
||||
|
||||
impl fmt::Debug for CodeObject {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let inst_str = self.instructions
|
||||
let inst_str = self
|
||||
.instructions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, inst)| format!("Inst {}: {:?}", i, inst))
|
||||
|
||||
@@ -14,7 +14,11 @@ struct Compiler {
|
||||
nxt_label: usize,
|
||||
}
|
||||
|
||||
pub fn compile(vm: &mut VirtualMachine, source: &String, mode: Mode) -> Result<PyObjectRef, String> {
|
||||
pub fn compile(
|
||||
vm: &mut VirtualMachine,
|
||||
source: &String,
|
||||
mode: Mode,
|
||||
) -> Result<PyObjectRef, String> {
|
||||
let mut compiler = Compiler::new();
|
||||
compiler.push_new_code_object();
|
||||
match mode {
|
||||
@@ -46,7 +50,7 @@ pub fn compile(vm: &mut VirtualMachine, source: &String, mode: Mode) -> Result<P
|
||||
}
|
||||
}
|
||||
compiler.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::None
|
||||
value: bytecode::Constant::None,
|
||||
});
|
||||
compiler.emit(Instruction::ReturnValue);
|
||||
}
|
||||
@@ -255,10 +259,11 @@ impl Compiler {
|
||||
}
|
||||
ast::Statement::ClassDef { name, body } => {
|
||||
self.emit(Instruction::LoadBuildClass);
|
||||
self.code_object_stack.push(
|
||||
CodeObject::new(vec![String::from("__locals__")]));
|
||||
self.code_object_stack
|
||||
.push(CodeObject::new(vec![String::from("__locals__")]));
|
||||
self.emit(Instruction::LoadName {
|
||||
name: String::from("__locals__")});
|
||||
name: String::from("__locals__"),
|
||||
});
|
||||
self.emit(Instruction::StoreLocals);
|
||||
self.compile_statements(body);
|
||||
self.emit(Instruction::LoadConst {
|
||||
@@ -378,7 +383,7 @@ impl Compiler {
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
self.compile_expression(value);
|
||||
self.emit(Instruction::StoreAttr {
|
||||
name: name.to_string()
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
@@ -423,7 +428,8 @@ impl Compiler {
|
||||
panic!("Not impl");
|
||||
}
|
||||
},
|
||||
_ => { // If all else fail, fall back to simple checking of boolean value:
|
||||
_ => {
|
||||
// If all else fail, fall back to simple checking of boolean value:
|
||||
self.compile_expression(expression);
|
||||
self.emit(Instruction::UnaryOperation {
|
||||
op: bytecode::UnaryOperator::Not,
|
||||
@@ -450,17 +456,17 @@ impl Compiler {
|
||||
self.compile_test(expression, not_label);
|
||||
// Load const True
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: true},
|
||||
value: bytecode::Constant::Boolean { value: true },
|
||||
});
|
||||
self.emit(Instruction::Jump { target: end_label });
|
||||
|
||||
self.set_label(not_label);
|
||||
// Load const False
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: false},
|
||||
value: bytecode::Constant::Boolean { value: false },
|
||||
});
|
||||
self.set_label(end_label);
|
||||
},
|
||||
}
|
||||
ast::Expression::Binop { a, op, b } => {
|
||||
self.compile_expression(&*a);
|
||||
self.compile_expression(&*b);
|
||||
@@ -546,12 +552,12 @@ impl Compiler {
|
||||
}
|
||||
ast::Expression::True => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: true},
|
||||
value: bytecode::Constant::Boolean { value: true },
|
||||
});
|
||||
}
|
||||
ast::Expression::False => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: false},
|
||||
value: bytecode::Constant::Boolean { value: false },
|
||||
});
|
||||
}
|
||||
ast::Expression::None => {
|
||||
|
||||
@@ -18,8 +18,8 @@ pub fn eval(vm: &mut VirtualMachine, source: &String, scope: PyObjectRef) -> PyR
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::VirtualMachine;
|
||||
use super::eval;
|
||||
use super::VirtualMachine;
|
||||
|
||||
#[test]
|
||||
fn test_print_42() {
|
||||
|
||||
@@ -36,10 +36,7 @@ pub fn copy_code(code_obj: PyObjectRef) -> bytecode::CodeObject {
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(
|
||||
code: PyObjectRef,
|
||||
globals: PyObjectRef,
|
||||
) -> Frame {
|
||||
pub fn new(code: PyObjectRef, globals: PyObjectRef) -> Frame {
|
||||
//populate the globals and locals
|
||||
//TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95
|
||||
/*
|
||||
@@ -106,12 +103,14 @@ impl Frame {
|
||||
|
||||
impl fmt::Debug for Frame {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let stack_str = self.stack
|
||||
let stack_str = self
|
||||
.stack
|
||||
.iter()
|
||||
.map(|elem| format!("\n > {}", elem.borrow_mut().str()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("");
|
||||
let block_str = self.blocks
|
||||
let block_str = self
|
||||
.blocks
|
||||
.iter()
|
||||
.map(|elem| format!("\n > {:?}", elem))
|
||||
.collect::<Vec<_>>()
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::path::PathBuf;
|
||||
|
||||
use self::rustpython_parser::parser;
|
||||
use super::compile;
|
||||
use super::pyobject::{PyObject, PyObjectKind, PyResult, DictProtocol};
|
||||
use super::pyobject::{DictProtocol, PyObject, PyObjectKind, PyResult};
|
||||
use super::vm::VirtualMachine;
|
||||
|
||||
fn import_module(vm: &mut VirtualMachine, module: &String) -> PyResult {
|
||||
@@ -64,10 +64,16 @@ pub fn import(vm: &mut VirtualMachine, module: &String, symbol: &Option<String>)
|
||||
|
||||
fn find_source(name: &String) -> io::Result<PathBuf> {
|
||||
let suffixes = [".py", "/__init__.py"];
|
||||
let filepaths = suffixes.iter().map(|suffix| format!("{}{}", name, suffix)).map(|filename| PathBuf::from(filename));
|
||||
let filepaths = suffixes
|
||||
.iter()
|
||||
.map(|suffix| format!("{}{}", name, suffix))
|
||||
.map(|filename| PathBuf::from(filename));
|
||||
|
||||
match filepaths.filter(|p| p.exists()).next() {
|
||||
Some(path) => Ok(path.to_path_buf()),
|
||||
None => Err(io::Error::new(NotFound, format!("Module ({}) could not be found.", name)))
|
||||
None => Err(io::Error::new(
|
||||
NotFound,
|
||||
format!("Module ({}) could not be found.", name),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ pub mod compile;
|
||||
pub mod eval;
|
||||
mod frame;
|
||||
mod import;
|
||||
mod objbool;
|
||||
mod objdict;
|
||||
mod objint;
|
||||
mod objlist;
|
||||
mod objsequence;
|
||||
mod objstr;
|
||||
mod objtype;
|
||||
mod objbool;
|
||||
pub mod pyobject;
|
||||
mod sysmodule;
|
||||
mod vm;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
use super::pyobject::{PyObjectKind, PyObjectRef};
|
||||
|
||||
pub fn boolval(o: PyObjectRef) -> bool {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyFuncArgs};
|
||||
use super::pyobject::{PyFuncArgs, PyObject, PyObjectKind, PyObjectRef};
|
||||
use super::vm::VirtualMachine;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn create_type(type_type: PyObjectRef) -> PyObjectRef {
|
||||
let typ = PyObject::new(
|
||||
PyObjectKind::Class {
|
||||
name: "int".to_string(),
|
||||
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone() ),
|
||||
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()),
|
||||
},
|
||||
type_type.clone(),
|
||||
);
|
||||
|
||||
@@ -11,11 +11,13 @@ pub fn create_type() -> PyObjectRef {
|
||||
let dict = PyObject::new(
|
||||
PyObjectKind::Dict {
|
||||
elements: HashMap::new(),
|
||||
}, typ.clone());
|
||||
},
|
||||
typ.clone(),
|
||||
);
|
||||
(*typ.borrow_mut()).kind = PyObjectKind::Class {
|
||||
name: String::from("type"),
|
||||
dict: dict,
|
||||
};
|
||||
name: String::from("type"),
|
||||
dict: dict,
|
||||
};
|
||||
(*typ.borrow_mut()).typ = Some(typ.clone());
|
||||
typ
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use super::bytecode;
|
||||
use super::objint;
|
||||
use super::objtype;
|
||||
use super::vm::VirtualMachine;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::ops::{Add, Div, Mul, Sub, Rem};
|
||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||
use std::rc::Rc;
|
||||
use super::vm::VirtualMachine;
|
||||
|
||||
/* Python objects and references.
|
||||
|
||||
@@ -53,8 +53,8 @@ pub struct PyContext {
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct Scope {
|
||||
pub locals: PyObjectRef, // Variables
|
||||
pub parent: Option<PyObjectRef>, // Parent scope
|
||||
pub locals: PyObjectRef, // Variables
|
||||
pub parent: Option<PyObjectRef>, // Parent scope
|
||||
}
|
||||
|
||||
// Basic objects:
|
||||
@@ -121,7 +121,10 @@ impl PyContext {
|
||||
locals: locals,
|
||||
parent: parent,
|
||||
};
|
||||
PyObject { kind: PyObjectKind::Scope { scope: scope }, typ: None }.into_ref()
|
||||
PyObject {
|
||||
kind: PyObjectKind::Scope { scope: scope },
|
||||
typ: None,
|
||||
}.into_ref()
|
||||
}
|
||||
|
||||
pub fn new_module(&self, name: &String, scope: PyObjectRef) -> PyObjectRef {
|
||||
@@ -142,10 +145,13 @@ impl PyContext {
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: String, namespace: PyObjectRef) -> PyObjectRef {
|
||||
PyObject::new(PyObjectKind::Class {
|
||||
name: name,
|
||||
dict: namespace.clone()
|
||||
}, self.type_type.clone())
|
||||
PyObject::new(
|
||||
PyObjectKind::Class {
|
||||
name: name,
|
||||
dict: namespace.clone(),
|
||||
},
|
||||
self.type_type.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
/* TODO: something like this?
|
||||
@@ -225,8 +231,7 @@ impl AttributeProtocol for PyObjectRef {
|
||||
|
||||
fn set_attr(&self, attr_name: &String, value: PyObjectRef) {
|
||||
match self.borrow_mut().kind {
|
||||
PyObjectKind::Instance { ref mut dict } =>
|
||||
dict.set_item(attr_name, value),
|
||||
PyObjectKind::Instance { ref mut dict } => dict.set_item(attr_name, value),
|
||||
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
|
||||
};
|
||||
}
|
||||
@@ -263,11 +268,14 @@ impl DictProtocol for PyObjectRef {
|
||||
elements: ref mut el,
|
||||
} => {
|
||||
el.insert(k.to_string(), v);
|
||||
},
|
||||
PyObjectKind::Module { name: _, ref mut dict } => dict.set_item(k, v),
|
||||
}
|
||||
PyObjectKind::Module {
|
||||
name: _,
|
||||
ref mut dict,
|
||||
} => dict.set_item(k, v),
|
||||
PyObjectKind::Scope { ref mut scope } => {
|
||||
scope.locals.set_item(k, v);
|
||||
},
|
||||
}
|
||||
_ => panic!("TODO"),
|
||||
};
|
||||
}
|
||||
@@ -342,7 +350,7 @@ pub enum PyObjectKind {
|
||||
dict: PyObjectRef,
|
||||
},
|
||||
Instance {
|
||||
dict: PyObjectRef
|
||||
dict: PyObjectRef,
|
||||
},
|
||||
RustFunction {
|
||||
function: RustPyFunc,
|
||||
@@ -359,8 +367,15 @@ impl fmt::Debug for PyObjectKind {
|
||||
&PyObjectKind::List { elements: _ } => write!(f, "list"),
|
||||
&PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"),
|
||||
&PyObjectKind::Dict { elements: _ } => write!(f, "dict"),
|
||||
&PyObjectKind::Iterator { position: _, iterated_obj: _ } => write!(f, "iterator"),
|
||||
&PyObjectKind::Slice { start: _, stop: _, step: _ } => write!(f, "slice"),
|
||||
&PyObjectKind::Iterator {
|
||||
position: _,
|
||||
iterated_obj: _,
|
||||
} => write!(f, "iterator"),
|
||||
&PyObjectKind::Slice {
|
||||
start: _,
|
||||
stop: _,
|
||||
step: _,
|
||||
} => write!(f, "slice"),
|
||||
&PyObjectKind::NameError { name: _ } => write!(f, "NameError"),
|
||||
&PyObjectKind::Code { ref code } => write!(f, "code: {:?}", code),
|
||||
&PyObjectKind::Function { code: _, scope: _ } => write!(f, "function"),
|
||||
@@ -427,10 +442,11 @@ impl PyObject {
|
||||
.join(", ")
|
||||
),
|
||||
PyObjectKind::None => String::from("None"),
|
||||
PyObjectKind::Class { ref name, dict: ref _dict } =>
|
||||
format!("<class '{}'>", name),
|
||||
PyObjectKind::Instance { dict: _ } =>
|
||||
format!("<instance>"),
|
||||
PyObjectKind::Class {
|
||||
ref name,
|
||||
dict: ref _dict,
|
||||
} => format!("<class '{}'>", name),
|
||||
PyObjectKind::Instance { dict: _ } => format!("<instance>"),
|
||||
PyObjectKind::Code { code: _ } => format!("<code>"),
|
||||
PyObjectKind::Function { code: _, scope: _ } => format!("<func>"),
|
||||
PyObjectKind::RustFunction { function: _ } => format!("<rustfunc>"),
|
||||
|
||||
59
vm/src/vm.rs
59
vm/src/vm.rs
@@ -103,7 +103,9 @@ impl VirtualMachine {
|
||||
let a2 = &*self.builtins.borrow();
|
||||
match a2.kind {
|
||||
PyObjectKind::Module { name: _, ref dict } => dict.clone(),
|
||||
_ => { panic!("OMG"); }
|
||||
_ => {
|
||||
panic!("OMG");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,10 +138,8 @@ impl VirtualMachine {
|
||||
loop {
|
||||
let block = self.pop_block();
|
||||
match block {
|
||||
Some(Block::Loop { start: _, end: __ }) => {
|
||||
break block.unwrap()
|
||||
},
|
||||
Some(Block::TryExcept {}) => {},
|
||||
Some(Block::Loop { start: _, end: __ }) => break block.unwrap(),
|
||||
Some(Block::TryExcept {}) => {}
|
||||
None => panic!("No block to break / continue"),
|
||||
}
|
||||
}
|
||||
@@ -150,15 +150,15 @@ impl VirtualMachine {
|
||||
loop {
|
||||
let block = self.pop_block();
|
||||
match block {
|
||||
Some(Block::TryExcept { }) => {
|
||||
Some(Block::TryExcept {}) => {
|
||||
// Exception handled?
|
||||
// TODO: how do we know if the exception is handled?
|
||||
let is_handled = true;
|
||||
if is_handled {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
Some(_) => {},
|
||||
}
|
||||
Some(_) => {}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ impl VirtualMachine {
|
||||
if scope.contains_key(name) {
|
||||
let obj = scope.get_item(name);
|
||||
self.push_value(obj);
|
||||
break None
|
||||
break None;
|
||||
} else if scope.has_parent() {
|
||||
scope = scope.get_parent();
|
||||
} else {
|
||||
@@ -204,7 +204,7 @@ impl VirtualMachine {
|
||||
},
|
||||
self.get_type(),
|
||||
);
|
||||
break Some(Err(name_error))
|
||||
break Some(Err(name_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ impl VirtualMachine {
|
||||
Some(Err(exception)) => {
|
||||
// unwind block stack on exception and find any handlers.
|
||||
match self.unwind_exception(exception) {
|
||||
None => {},
|
||||
None => {}
|
||||
Some(exception) => break Err(exception),
|
||||
}
|
||||
}
|
||||
@@ -463,7 +463,7 @@ impl VirtualMachine {
|
||||
fn new_instance(&mut self, type_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
// more or less __new__ operator
|
||||
let dict = self.new_dict();
|
||||
let obj = PyObject::new(PyObjectKind::Instance{dict: dict}, type_ref.clone());
|
||||
let obj = PyObject::new(PyObjectKind::Instance { dict: dict }, type_ref.clone());
|
||||
let init = type_ref.get_attr(&String::from("__init__"));
|
||||
let mut self_args = PyFuncArgs { args: args.args };
|
||||
self_args.args.insert(0, obj.clone());
|
||||
@@ -477,7 +477,10 @@ impl VirtualMachine {
|
||||
|
||||
match f.kind {
|
||||
PyObjectKind::RustFunction { function: _ } => f.call(self, args),
|
||||
PyObjectKind::Function { ref code, ref scope } => {
|
||||
PyObjectKind::Function {
|
||||
ref code,
|
||||
ref scope,
|
||||
} => {
|
||||
let mut scope = self.ctx.new_scope(Some(scope.clone()));
|
||||
let code_object = copy_code(code.clone());
|
||||
for (name, value) in code_object.arg_names.iter().zip(args.args) {
|
||||
@@ -486,8 +489,7 @@ impl VirtualMachine {
|
||||
let frame = Frame::new(code.clone(), scope);
|
||||
self.run_frame(frame)
|
||||
}
|
||||
PyObjectKind::Class { name: _, dict: _ } =>
|
||||
self.new_instance(func_ref.clone(), args),
|
||||
PyObjectKind::Class { name: _, dict: _ } => self.new_instance(func_ref.clone(), args),
|
||||
ref kind => {
|
||||
unimplemented!("invoke unimplemented for: {:?}", kind);
|
||||
}
|
||||
@@ -608,8 +610,7 @@ impl VirtualMachine {
|
||||
PyObjectKind::Integer { value } => Some(value),
|
||||
PyObjectKind::None => None,
|
||||
_ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x),
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
|
||||
let start = out[0];
|
||||
let stop = out[1];
|
||||
@@ -691,16 +692,20 @@ impl VirtualMachine {
|
||||
// pop argc arguments
|
||||
// argument: name, args, globals
|
||||
let scope = self.current_frame().locals.clone();
|
||||
let obj = PyObject::new(PyObjectKind::Function { code: code_obj, scope: scope }, self.get_type());
|
||||
let obj = PyObject::new(
|
||||
PyObjectKind::Function {
|
||||
code: code_obj,
|
||||
scope: scope,
|
||||
},
|
||||
self.get_type(),
|
||||
);
|
||||
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 args = PyFuncArgs { args: args };
|
||||
let func_ref = self.pop_value();
|
||||
|
||||
// Call function:
|
||||
@@ -773,8 +778,7 @@ impl VirtualMachine {
|
||||
bytecode::Instruction::PrintExpr => {
|
||||
let expr = self.pop_value();
|
||||
match expr.borrow().kind {
|
||||
PyObjectKind::None =>
|
||||
(),
|
||||
PyObjectKind::None => (),
|
||||
_ => {
|
||||
builtins::builtin_print(
|
||||
self,
|
||||
@@ -789,9 +793,9 @@ impl VirtualMachine {
|
||||
bytecode::Instruction::LoadBuildClass => {
|
||||
let rustfunc = PyObject::new(
|
||||
PyObjectKind::RustFunction {
|
||||
function: builtins::builtin_build_class_
|
||||
function: builtins::builtin_build_class_,
|
||||
},
|
||||
objtype::create_type()
|
||||
objtype::create_type(),
|
||||
);
|
||||
self.push_value(rustfunc);
|
||||
None
|
||||
@@ -803,11 +807,10 @@ impl VirtualMachine {
|
||||
PyObjectKind::Scope { ref mut scope } => {
|
||||
scope.locals = locals;
|
||||
}
|
||||
_ =>
|
||||
panic!("We really expect our scope to be a scope!")
|
||||
_ => panic!("We really expect our scope to be a scope!"),
|
||||
}
|
||||
None
|
||||
},
|
||||
}
|
||||
_ => panic!("NOT IMPL {:?}", instruction),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user