Skip to content

Commit 1e3b45e

Browse files
committed
Add complex basic type
1 parent 5053d6d commit 1e3b45e

16 files changed

+149
-10
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

parser/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,4 +300,5 @@ pub enum Comparison {
300300
pub enum Number {
301301
Integer { value: i32 },
302302
Float { value: f64 },
303+
Complex { real: f64, imag: f64 },
303304
}

parser/src/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub enum Tok {
44
Name { name: String },
55
Number { value: String },
6+
Complex { real: f64, imag: f64 },
67
String { value: String },
78
Bytes { value: Vec<u8> },
89
Newline,

tests/snippets/basic_types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@
3737
pass
3838

3939
assert int() == 0
40+
41+
a = complex(2, 4)
42+
assert type(a) is complex
43+
assert type(a + a) is complex

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ authors = ["Shing Lyu <[email protected]>"]
55

66
[dependencies]
77
bitflags = "1.0.4"
8+
num-complex = "0.2"
89
log = "0.3"
910
rustpython_parser = {path = "../parser"}
1011
serde = "1.0.66"

vm/src/builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
126126
compile::compile(vm, &source, mode, None)
127127
}
128128

129-
// builtin_complex
130129
// builtin_delattr
131130

132131
fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -543,6 +542,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
543542
dict.insert(String::from("bytes"), ctx.bytes_type());
544543
dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr));
545544
dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile));
545+
dict.insert(String::from("complex"), ctx.complex_type());
546546
dict.insert(String::from("dict"), ctx.dict_type());
547547
dict.insert(String::from("divmod"), ctx.new_rustfunc(builtin_divmod));
548548
dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir));

vm/src/bytecode.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ let call_function = 0x64;
1010
/*
1111
* Primitive instruction type, which can be encoded and decoded.
1212
*/
13-
extern crate rustpython_parser;
1413

15-
use self::rustpython_parser::ast;
14+
use num_complex::Complex64;
15+
use rustpython_parser::ast;
1616
use std::collections::HashMap;
1717
use std::fmt;
1818

@@ -197,6 +197,7 @@ pub enum CallType {
197197
pub enum Constant {
198198
Integer { value: i32 }, // TODO: replace by arbitrary big int math.
199199
Float { value: f64 },
200+
Complex { value: Complex64 },
200201
Boolean { value: bool },
201202
String { value: String },
202203
Bytes { value: Vec<u8> },

vm/src/compile.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
* https://github.com/micropython/micropython/blob/master/py/compile.c
77
*/
88

9-
extern crate rustpython_parser;
10-
11-
use self::rustpython_parser::{ast, parser};
129
use super::bytecode::{self, CallType, CodeObject, Instruction};
1310
use super::pyobject::{PyObject, PyObjectKind, PyResult};
1411
use super::vm::VirtualMachine;
12+
use num_complex::Complex64;
13+
use rustpython_parser::{ast, parser};
1514

1615
struct Compiler {
1716
code_object_stack: Vec<CodeObject>,
@@ -846,6 +845,9 @@ impl Compiler {
846845
let const_value = match value {
847846
ast::Number::Integer { value } => bytecode::Constant::Integer { value: *value },
848847
ast::Number::Float { value } => bytecode::Constant::Float { value: *value },
848+
ast::Number::Complex { real, imag } => bytecode::Constant::Complex {
849+
value: Complex64::new(*real, *imag),
850+
},
849851
};
850852
self.emit(Instruction::LoadConst { value: const_value });
851853
}
@@ -1301,8 +1303,8 @@ mod tests {
13011303
use super::bytecode::CodeObject;
13021304
use super::bytecode::Constant::*;
13031305
use super::bytecode::Instruction::*;
1304-
use super::rustpython_parser::parser;
13051306
use super::Compiler;
1307+
use rustpython_parser::parser;
13061308
fn compile_exec(source: &str) -> CodeObject {
13071309
let mut compiler = Compiler::new();
13081310
compiler.push_new_code_object(Option::None, "<module>".to_string());

vm/src/frame.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@ impl Frame {
10741074
match *value {
10751075
bytecode::Constant::Integer { ref value } => vm.ctx.new_int(*value),
10761076
bytecode::Constant::Float { ref value } => vm.ctx.new_float(*value),
1077+
bytecode::Constant::Complex { ref value } => vm.ctx.new_complex(*value),
10771078
bytecode::Constant::String { ref value } => vm.new_str(value.clone()),
10781079
bytecode::Constant::Bytes { ref value } => vm.ctx.new_bytes(value.clone()),
10791080
bytecode::Constant::Boolean { ref value } => vm.new_bool(value.clone()),

vm/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ extern crate bitflags;
33
#[macro_use]
44
extern crate log;
55
// extern crate env_logger;
6+
extern crate num_complex;
67
extern crate serde;
78
extern crate serde_json;
89

10+
extern crate rustpython_parser;
11+
912
//extern crate eval; use eval::eval::*;
1013
// use py_code_object::{Function, NativeType, PyCodeObject};
1114

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod objbool;
22
pub mod objbytes;
3+
pub mod objcomplex;
34
pub mod objdict;
45
pub mod objfloat;
56
pub mod objfunction;

vm/src/obj/objcomplex.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use super::super::pyobject::{
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
3+
TypeProtocol,
4+
};
5+
use super::super::vm::VirtualMachine;
6+
use super::objfloat;
7+
use super::objtype;
8+
use num_complex::Complex64;
9+
10+
pub fn init(context: &PyContext) {
11+
let ref complex_type = context.complex_type;
12+
complex_type.set_attr("__add__", context.new_rustfunc(complex_add));
13+
complex_type.set_attr("__new__", context.new_rustfunc(complex_new));
14+
complex_type.set_attr("__repr__", context.new_rustfunc(complex_repr));
15+
}
16+
17+
pub fn get_value(obj: &PyObjectRef) -> Complex64 {
18+
if let PyObjectKind::Complex { value } = &obj.borrow().kind {
19+
*value
20+
} else {
21+
panic!("Inner error getting complex");
22+
}
23+
}
24+
25+
fn complex_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
26+
arg_check!(
27+
vm,
28+
args,
29+
required = [(cls, None)],
30+
optional = [(real, None), (imag, None)]
31+
);
32+
33+
if !objtype::issubclass(cls, &vm.ctx.complex_type()) {
34+
return Err(vm.new_type_error(format!("{:?} is not a subtype of complex", cls)));
35+
}
36+
37+
let real = match real {
38+
None => 0.0,
39+
Some(value) => objfloat::make_float(vm, value)?,
40+
};
41+
42+
let imag = match imag {
43+
None => 0.0,
44+
Some(value) => objfloat::make_float(vm, value)?,
45+
};
46+
47+
let value = Complex64::new(real, imag);
48+
49+
Ok(PyObject::new(PyObjectKind::Complex { value }, cls.clone()))
50+
}
51+
52+
fn complex_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
53+
arg_check!(
54+
vm,
55+
args,
56+
required = [(i, Some(vm.ctx.complex_type())), (i2, None)]
57+
);
58+
59+
let v1 = get_value(i);
60+
if objtype::isinstance(i2, &vm.ctx.complex_type()) {
61+
Ok(vm.ctx.new_complex(v1 + get_value(i2)))
62+
} else {
63+
Err(vm.new_type_error(format!("Cannot add {:?} and {:?}", i, i2)))
64+
}
65+
}
66+
67+
fn complex_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
68+
arg_check!(vm, args, required = [(obj, Some(vm.ctx.complex_type()))]);
69+
let v = get_value(obj);
70+
Ok(vm.new_str(v.to_string()))
71+
}

vm/src/obj/objfloat.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::super::vm::VirtualMachine;
55
use super::objint;
66
use super::objtype;
77

8-
fn float_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
8+
fn float_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
99
arg_check!(vm, args, required = [(float, Some(vm.ctx.float_type()))]);
1010
let v = get_value(float);
1111
Ok(vm.new_str(v.to_string()))
@@ -38,6 +38,16 @@ pub fn get_value(obj: &PyObjectRef) -> f64 {
3838
}
3939
}
4040

41+
pub fn make_float(vm: &mut VirtualMachine, obj: &PyObjectRef) -> Result<f64, PyObjectRef> {
42+
if objtype::isinstance(obj, &vm.ctx.float_type()) {
43+
Ok(get_value(obj))
44+
} else if objtype::isinstance(obj, &vm.ctx.int_type()) {
45+
Ok(objint::get_value(obj) as f64)
46+
} else {
47+
Err(vm.new_type_error(format!("Cannot cast {:?} to float", obj)))
48+
}
49+
}
50+
4151
fn set_value(obj: &PyObjectRef, value: f64) {
4252
obj.borrow_mut().kind = PyObjectKind::Float { value };
4353
}

vm/src/obj/objlist.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::super::pyobject::{
2-
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
3+
TypeProtocol,
34
};
45
use super::super::vm::VirtualMachine;
56
use super::objbool;
@@ -56,7 +57,10 @@ fn list_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5657
}
5758
};
5859

59-
Ok(vm.ctx.new_list(elements))
60+
Ok(PyObject::new(
61+
PyObjectKind::List { elements: elements },
62+
cls.clone(),
63+
))
6064
}
6165

6266
fn list_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

vm/src/pyobject.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::exceptions;
33
use super::frame::Frame;
44
use super::obj::objbool;
55
use super::obj::objbytes;
6+
use super::obj::objcomplex;
67
use super::obj::objdict;
78
use super::obj::objfloat;
89
use super::obj::objfunction;
@@ -16,6 +17,7 @@ use super::obj::objstr;
1617
use super::obj::objtuple;
1718
use super::obj::objtype;
1819
use super::vm::VirtualMachine;
20+
use num_complex::Complex64;
1921
use std::cell::RefCell;
2022
use std::collections::HashMap;
2123
use std::fmt;
@@ -57,6 +59,7 @@ pub struct PyContext {
5759
pub dict_type: PyObjectRef,
5860
pub int_type: PyObjectRef,
5961
pub float_type: PyObjectRef,
62+
pub complex_type: PyObjectRef,
6063
pub bytes_type: PyObjectRef,
6164
pub bool_type: PyObjectRef,
6265
pub true_value: PyObjectRef,
@@ -130,6 +133,7 @@ impl PyContext {
130133
let set_type = create_type("set", &type_type, &object_type, &dict_type);
131134
let int_type = create_type("int", &type_type, &object_type, &dict_type);
132135
let float_type = create_type("float", &type_type, &object_type, &dict_type);
136+
let complex_type = create_type("complex", &type_type, &object_type, &dict_type);
133137
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
134138
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
135139
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
@@ -146,6 +150,7 @@ impl PyContext {
146150
let context = PyContext {
147151
int_type: int_type,
148152
float_type: float_type,
153+
complex_type: complex_type,
149154
bytes_type: bytes_type,
150155
list_type: list_type,
151156
set_type: set_type,
@@ -176,6 +181,7 @@ impl PyContext {
176181
objgenerator::init(&context);
177182
objint::init(&context);
178183
objfloat::init(&context);
184+
objcomplex::init(&context);
179185
objbytes::init(&context);
180186
objstr::init(&context);
181187
objtuple::init(&context);
@@ -193,6 +199,10 @@ impl PyContext {
193199
self.float_type.clone()
194200
}
195201

202+
pub fn complex_type(&self) -> PyObjectRef {
203+
self.complex_type.clone()
204+
}
205+
196206
pub fn bytes_type(&self) -> PyObjectRef {
197207
self.bytes_type.clone()
198208
}
@@ -262,6 +272,10 @@ impl PyContext {
262272
PyObject::new(PyObjectKind::Float { value: i }, self.float_type())
263273
}
264274

275+
pub fn new_complex(&self, i: Complex64) -> PyObjectRef {
276+
PyObject::new(PyObjectKind::Complex { value: i }, self.complex_type())
277+
}
278+
265279
pub fn new_str(&self, s: String) -> PyObjectRef {
266280
PyObject::new(PyObjectKind::String { value: s }, self.str_type())
267281
}
@@ -624,6 +638,9 @@ pub enum PyObjectKind {
624638
Float {
625639
value: f64,
626640
},
641+
Complex {
642+
value: Complex64,
643+
},
627644
Bytes {
628645
value: Vec<u8>,
629646
},
@@ -690,6 +707,7 @@ impl fmt::Debug for PyObjectKind {
690707
&PyObjectKind::String { ref value } => write!(f, "str \"{}\"", value),
691708
&PyObjectKind::Integer { ref value } => write!(f, "int {}", value),
692709
&PyObjectKind::Float { ref value } => write!(f, "float {}", value),
710+
&PyObjectKind::Complex { ref value } => write!(f, "complex {}", value),
693711
&PyObjectKind::Bytes { ref value } => write!(f, "bytes {:?}", value),
694712
&PyObjectKind::List { elements: _ } => write!(f, "list"),
695713
&PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"),
@@ -740,6 +758,7 @@ impl PyObject {
740758
PyObjectKind::String { ref value } => value.clone(),
741759
PyObjectKind::Integer { ref value } => format!("{:?}", value),
742760
PyObjectKind::Float { ref value } => format!("{:?}", value),
761+
PyObjectKind::Complex { ref value } => format!("{:?}", value),
743762
PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value),
744763
PyObjectKind::List { ref elements } => format!(
745764
"[{}]",

vm/src/stdlib/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use super::super::pyobject::{
1313
AttributeProtocol, DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol,
1414
};
1515
use super::super::VirtualMachine;
16+
use num_complex::Complex64;
1617
use std::ops::Deref;
1718

1819
/*
@@ -391,6 +392,9 @@ fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectR
391392
let py_n = match value {
392393
ast::Number::Integer { value } => ctx.new_int(*value),
393394
ast::Number::Float { value } => ctx.new_float(*value),
395+
ast::Number::Complex { real, imag } => {
396+
ctx.new_complex(Complex64::new(*real, *imag))
397+
}
394398
};
395399
node.set_attr("n", py_n);
396400

0 commit comments

Comments
 (0)