Skip to content

Commit b7a0b0f

Browse files
committed
Removal of ToRust trait to prevent incorrect str representation
1 parent 4be2f24 commit b7a0b0f

15 files changed

+87
-71
lines changed

parser/src/ast.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/*
2-
* Implement abstract syntax tree nodes for the python language.
3-
*/
1+
//! Implement abstract syntax tree nodes for the python language.
2+
//!
3+
//! Roughly equivalent to this: https://docs.python.org/3/library/ast.html
44
55
pub use super::lexer::Location;
66
/*
@@ -40,6 +40,7 @@ pub struct Located<T> {
4040

4141
pub type LocatedStatement = Located<Statement>;
4242

43+
/// Abstract syntax tree nodes for python statements.
4344
#[derive(Debug, PartialEq)]
4445
pub enum Statement {
4546
Break,

parser/src/lexer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! This module takes care of lexing python source text. This means source
2+
//! code is translated into seperate tokens.
3+
14
pub use super::token::Tok;
25
use std::collections::HashMap;
36

parser/src/parser.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, String> {
6969
do_lalr_parsing!(source, Statement, StartStatement)
7070
}
7171

72+
/// Parses a python expression
73+
///
74+
/// # Example
75+
/// ```
76+
/// use rustpython_parser::{parser, ast};
77+
/// let expr = parser::parse_expression("1+2").unwrap();
78+
///
79+
/// assert_eq!(ast::Expression::Binop {
80+
/// a: Box::new(ast::Expression::Number {
81+
/// value: ast::Number::Integer { value: 1 }
82+
/// }),
83+
/// op: ast::Operator::Add,
84+
/// b: Box::new(ast::Expression::Number {
85+
/// value: ast::Number::Integer { value: 2 }
86+
/// })
87+
/// },
88+
/// expr);
89+
///
90+
/// ```
7291
pub fn parse_expression(source: &str) -> Result<ast::Expression, String> {
7392
do_lalr_parsing!(source, Expression, StartExpression)
7493
}

vm/src/builtins.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//! Builtin function definitions.
2+
//!
3+
//! Implements functions listed here: https://docs.python.org/3/library/builtins.html
4+
15
// use std::ops::Deref;
26
use std::char;
37
use std::collections::HashMap;
@@ -463,10 +467,8 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
463467
pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
464468
trace!("print called with {:?}", args);
465469
for a in args.args {
466-
let s = match vm.to_str(a) {
467-
Ok(v) => objstr::get_value(&v),
468-
Err(err) => return Err(err),
469-
};
470+
let v = vm.to_str(&a)?;
471+
let s = objstr::get_value(&v);
470472
print!("{}", s);
471473
}
472474
println!();

vm/src/compile.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/*
2-
* Take an AST and transform it into bytecode
3-
*
4-
* Inspirational code:
5-
* https://github.com/python/cpython/blob/master/Python/compile.c
6-
* https://github.com/micropython/micropython/blob/master/py/compile.c
7-
*/
1+
//!
2+
//!
3+
//! Take an AST and transform it into bytecode
4+
//!
5+
//! Inspirational code:
6+
//! https://github.com/python/cpython/blob/master/Python/compile.c
7+
//! https://github.com/micropython/micropython/blob/master/py/compile.c
88
99
use super::bytecode::{self, CallType, CodeObject, Instruction};
1010
use super::pyobject::{PyObject, PyObjectKind, PyResult};
@@ -19,6 +19,7 @@ struct Compiler {
1919
current_source_location: ast::Location,
2020
}
2121

22+
/// Compile a given sourcecode into a bytecode object.
2223
pub fn compile(
2324
vm: &mut VirtualMachine,
2425
source: &str,

vm/src/exceptions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ pub fn print_exception(vm: &mut VirtualMachine, exc: &PyObjectRef) {
3030
for element in elements.iter() {
3131
if objtype::isinstance(&element, &vm.ctx.tuple_type()) {
3232
let element = objtuple::get_elements(&element);
33-
let filename = if let Ok(x) = vm.to_str(element[0].clone()) {
33+
let filename = if let Ok(x) = vm.to_str(&element[0]) {
3434
objstr::get_value(&x)
3535
} else {
3636
"<error>".to_string()
3737
};
3838

39-
let lineno = if let Ok(x) = vm.to_str(element[1].clone()) {
39+
let lineno = if let Ok(x) = vm.to_str(&element[1]) {
4040
objstr::get_value(&x)
4141
} else {
4242
"<error>".to_string()
4343
};
4444

45-
let obj_name = if let Ok(x) = vm.to_str(element[2].clone()) {
45+
let obj_name = if let Ok(x) = vm.to_str(&element[2]) {
4646
objstr::get_value(&x)
4747
} else {
4848
"<error>".to_string()
@@ -58,7 +58,7 @@ pub fn print_exception(vm: &mut VirtualMachine, exc: &PyObjectRef) {
5858
println!("No traceback set on exception");
5959
}
6060

61-
match vm.to_str(exc.clone()) {
61+
match vm.to_str(exc) {
6262
Ok(txt) => println!("{}", objstr::get_value(&txt)),
6363
Err(err) => println!("Error during error {:?}", err),
6464
}

vm/src/frame.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use super::obj::objstr;
1616
use super::obj::objtype;
1717
use super::pyobject::{
1818
AttributeProtocol, DictProtocol, IdProtocol, ParentProtocol, PyFuncArgs, PyObject,
19-
PyObjectKind, PyObjectRef, PyResult, ToRust, TypeProtocol,
19+
PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
2020
};
2121
use super::vm::VirtualMachine;
2222
use num_bigint::ToBigInt;
@@ -461,9 +461,8 @@ impl Frame {
461461
let kwarg_names = self.pop_value();
462462
let args: Vec<PyObjectRef> = self.pop_multiple(*count);
463463

464-
let kwarg_names = kwarg_names
465-
.to_vec()
466-
.unwrap()
464+
let kwarg_names = vm
465+
.extract_elements(&kwarg_names)?
467466
.iter()
468467
.map(|pyobj| objstr::get_value(pyobj))
469468
.collect();

vm/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
//! This crate contains most python logic.
2+
//!
3+
//! - Compilation
4+
//! - Bytecode
5+
//! - Import mechanics
6+
//! - Base objects
7+
18
#[macro_use]
29
extern crate bitflags;
310
#[macro_use]

vm/src/macros.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@ macro_rules! arg_check {
6464
match expected_type {
6565
Some(expected_type) => {
6666
if !objtype::isinstance(arg, &expected_type) {
67-
let arg_typ = arg.typ().clone();
68-
let actual_type = arg_typ.borrow().str().clone();
67+
let arg_typ = arg.typ();
68+
let expected_type_name = $vm.to_pystr(expected_type)?;
69+
let actual_type = $vm.to_pystr(&arg_typ)?;
6970
return Err($vm.new_type_error(format!(
7071
"argument of type {} is required for parameter {} ({}) (got: {})",
71-
expected_type.borrow().str(),
72+
expected_type_name,
7273
arg_position + 1,
7374
arg_name,
7475
actual_type

vm/src/obj/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! This package contains the python basic/builtin types
2+
13
pub mod objbool;
24
pub mod objbytes;
35
pub mod objcomplex;

vm/src/obj/objstr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ fn str_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
246246
panic!("str expects exactly one parameter");
247247
};
248248

249-
vm.to_str(args.args[1].clone())
249+
vm.to_str(&args.args[1])
250250
}
251251

252252
impl PySliceableSequence for String {

vm/src/obj/objtuple.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@ fn tuple_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6262

6363
let mut str_parts = vec![];
6464
for elem in elements.iter() {
65-
match vm.to_repr(elem) {
66-
Ok(s) => str_parts.push(objstr::get_value(&s)),
67-
Err(err) => return Err(err),
68-
}
65+
let s = vm.to_repr(elem)?;
66+
str_parts.push(objstr::get_value(&s));
6967
}
7068

7169
let s = if str_parts.len() == 1 {

vm/src/obj/objtype.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::super::pyobject::{
22
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef,
3-
PyResult, ToRust, TypeProtocol,
3+
PyResult, TypeProtocol,
44
};
55
use super::super::vm::VirtualMachine;
66
use super::objdict;
@@ -99,16 +99,14 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9999
required = [
100100
(typ, Some(vm.ctx.type_type())),
101101
(name, Some(vm.ctx.str_type())),
102-
// bases needs to be mutable, which arg_check! doesn't support, so we just check
103-
// the type and extract it again below
104-
// TODO: arg_check! should support specifying iterables
105-
(_bases, None),
102+
(bases, None),
106103
(dict, Some(vm.ctx.dict_type()))
107104
]
108105
);
109-
let mut bases = args.args[2].to_vec().unwrap();
106+
let mut bases = vm.extract_elements(bases)?;
110107
bases.push(vm.context().object());
111-
new(typ.clone(), &name.to_str().unwrap(), bases, dict.clone())
108+
let name = objstr::get_value(name);
109+
new(typ.clone(), &name, bases, dict.clone())
112110
} else {
113111
Err(vm.new_type_error(format!(": type_new: {:?}", args)))
114112
}
@@ -124,15 +122,11 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
124122
};
125123

126124
if let Some(init) = obj.typ().get_attr("__init__") {
127-
match vm.invoke(init, args.insert(obj.clone())) {
128-
Ok(res) => {
129-
// TODO: assert that return is none?
130-
if !isinstance(&res, &vm.get_none()) {
131-
// panic!("__init__ must return none");
132-
// return Err(vm.new_type_error("__init__ must return None".to_string()));
133-
}
134-
}
135-
Err(err) => return Err(err),
125+
let res = vm.invoke(init, args.insert(obj.clone()))?;
126+
// TODO: assert that return is none?
127+
if !isinstance(&res, &vm.get_none()) {
128+
// panic!("__init__ must return none");
129+
// return Err(vm.new_type_error("__init__ must return None".to_string()));
136130
}
137131
}
138132
Ok(obj)

vm/src/pyobject.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -579,25 +579,6 @@ impl DictProtocol for PyObjectRef {
579579
}
580580
}
581581

582-
pub trait ToRust {
583-
fn to_vec(&self) -> Option<Vec<PyObjectRef>>;
584-
fn to_str(&self) -> Option<String>;
585-
}
586-
587-
impl ToRust for PyObjectRef {
588-
fn to_vec(&self) -> Option<Vec<PyObjectRef>> {
589-
match self.borrow().kind {
590-
PyObjectKind::Tuple { ref elements } => Some(elements.clone()),
591-
PyObjectKind::List { ref elements } => Some(elements.clone()),
592-
_ => None,
593-
}
594-
}
595-
596-
fn to_str(&self) -> Option<String> {
597-
Some(self.borrow().str())
598-
}
599-
}
600-
601582
impl fmt::Debug for PyObject {
602583
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603584
write!(f, "[PyObj {:?}]", self.kind)
@@ -772,6 +753,7 @@ impl PyObject {
772753
.into_ref()
773754
}
774755

756+
/// Deprecated method, please call `vm.to_pystr`
775757
pub fn str(&self) -> String {
776758
match self.kind {
777759
PyObjectKind::String { ref value } => value.clone(),

vm/src/vm.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/*
2-
* Implement virtual machine to run instructions.
3-
* See also:
4-
* https://github.com/ProgVal/pythonvm-rust/blob/master/src/processor/mod.rs
5-
*/
1+
//! Implement virtual machine to run instructions.
2+
//!
3+
//! See also:
4+
//! https://github.com/ProgVal/pythonvm-rust/blob/master/src/processor/mod.rs
5+
//!
66
77
extern crate rustpython_parser;
88

@@ -14,6 +14,7 @@ use super::frame::{copy_code, Frame};
1414
use super::obj::objgenerator;
1515
use super::obj::objiter;
1616
use super::obj::objlist;
17+
use super::obj::objstr;
1718
use super::obj::objtuple;
1819
use super::obj::objtype;
1920
use super::pyobject::{
@@ -40,6 +41,7 @@ impl VirtualMachine {
4041
frame.run_frame_full(self)
4142
}
4243

44+
/// Create a new python string object.
4345
pub fn new_str(&self, s: String) -> PyObjectRef {
4446
self.ctx.new_str(s)
4547
}
@@ -141,10 +143,15 @@ impl VirtualMachine {
141143
}
142144

143145
// Container of the virtual machine state:
144-
pub fn to_str(&mut self, obj: PyObjectRef) -> PyResult {
146+
pub fn to_str(&mut self, obj: &PyObjectRef) -> PyResult {
145147
self.call_method(&obj, "__str__", vec![])
146148
}
147149

150+
pub fn to_pystr(&mut self, obj: &PyObjectRef) -> Result<String, PyObjectRef> {
151+
let py_str_obj = self.to_str(obj)?;
152+
Ok(objstr::get_value(&py_str_obj))
153+
}
154+
148155
pub fn to_repr(&mut self, obj: &PyObjectRef) -> PyResult {
149156
self.call_method(obj, "__repr__", vec![])
150157
}

0 commit comments

Comments
 (0)