Skip to content

Commit b5dc5a2

Browse files
committed
Merge branch 'master' into int_new_args
# Conflicts: # vm/src/function.rs
2 parents 6fd6cc6 + 6618def commit b5dc5a2

36 files changed

+858
-998
lines changed

Cargo.lock

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

parser/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ build = "build.rs"
66
edition = "2018"
77

88
[build-dependencies]
9-
lalrpop="0.15.1"
9+
lalrpop="0.16.3"
1010

1111
[dependencies]
12-
lalrpop-util="0.15.1"
12+
lalrpop-util="0.16.3"
1313
log="0.4.1"
1414
regex="0.2.2"
1515
num-bigint = "0.2"

parser/build.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use lalrpop;
22

33
fn main() {
4-
lalrpop::process_root().unwrap();
4+
lalrpop::Configuration::new()
5+
.generate_in_source_tree()
6+
.process()
7+
.unwrap();
58
}

parser/src/token.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use num_bigint::BigInt;
44

55
/// Python source code can be tokenized in a sequence of these tokens.
6-
#[derive(Debug, PartialEq)]
6+
#[derive(Clone, Debug, PartialEq)]
77
pub enum Tok {
88
Name { name: String },
99
Int { value: BigInt },

tests/.travis-runner.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pip install pipenv
1313
if [ $CODE_COVERAGE = "true" ]
1414
then
1515
find . -name '*.gcda' -delete
16+
find . -name '*.gcno' -delete
1617

1718
export CARGO_INCREMENTAL=0
1819
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads"

tests/snippets/builtin_format.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@
77
assert format({}) == "{}"
88

99
assert_raises(TypeError, lambda: format({}, 'b'), 'format_spec not empty for dict')
10+
11+
class BadFormat:
12+
def __format__(self, spec):
13+
return 42
14+
assert_raises(TypeError, lambda: format(BadFormat()))

vm/src/builtins.rs

Lines changed: 72 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6,103 +6,76 @@ use std::char;
66
use std::io::{self, Write};
77
use std::path::PathBuf;
88

9-
use num_traits::{Signed, ToPrimitive};
9+
use num_traits::Signed;
1010

1111
use crate::compile;
1212
use crate::import::import_module;
1313
use crate::obj::objbool;
14-
use crate::obj::objint;
14+
use crate::obj::objdict::PyDictRef;
15+
use crate::obj::objint::{self, PyIntRef};
1516
use crate::obj::objiter;
16-
use crate::obj::objstr::{self, PyStringRef};
17+
use crate::obj::objstr::{self, PyString, PyStringRef};
1718
use crate::obj::objtype::{self, PyClassRef};
1819

1920
use crate::frame::Scope;
2021
use crate::function::{Args, OptionalArg, PyFuncArgs};
2122
use crate::pyobject::{
22-
DictProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
23+
DictProtocol, IdProtocol, PyContext, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
24+
TypeProtocol,
2325
};
2426
use crate::vm::VirtualMachine;
2527

2628
use crate::obj::objcode::PyCodeRef;
2729
#[cfg(not(target_arch = "wasm32"))]
2830
use crate::stdlib::io::io_open;
2931

30-
fn get_locals(vm: &VirtualMachine) -> PyObjectRef {
31-
vm.get_locals()
32-
}
33-
34-
fn dir_locals(vm: &VirtualMachine) -> PyObjectRef {
35-
get_locals(vm)
36-
}
37-
38-
fn builtin_abs(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
39-
arg_check!(vm, args, required = [(x, None)]);
32+
fn builtin_abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
4033
match vm.get_method(x.clone(), "__abs__") {
4134
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![], vec![])),
4235
Err(..) => Err(vm.new_type_error("bad operand for abs".to_string())),
4336
}
4437
}
4538

46-
fn builtin_all(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
47-
arg_check!(vm, args, required = [(iterable, None)]);
48-
let items = vm.extract_elements(iterable)?;
49-
for item in items {
50-
let result = objbool::boolval(vm, item)?;
51-
if !result {
52-
return Ok(vm.new_bool(false));
39+
fn builtin_all(iterable: PyIterable<bool>, vm: &VirtualMachine) -> PyResult<bool> {
40+
for item in iterable.iter(vm)? {
41+
if !item? {
42+
return Ok(false);
5343
}
5444
}
55-
Ok(vm.new_bool(true))
45+
Ok(true)
5646
}
5747

58-
fn builtin_any(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
59-
arg_check!(vm, args, required = [(iterable, None)]);
60-
let iterator = objiter::get_iter(vm, iterable)?;
61-
62-
while let Some(item) = objiter::get_next_object(vm, &iterator)? {
63-
let result = objbool::boolval(vm, item)?;
64-
if result {
65-
return Ok(vm.new_bool(true));
48+
fn builtin_any(iterable: PyIterable<bool>, vm: &VirtualMachine) -> PyResult<bool> {
49+
for item in iterable.iter(vm)? {
50+
if item? {
51+
return Ok(true);
6652
}
6753
}
68-
69-
Ok(vm.new_bool(false))
54+
Ok(false)
7055
}
7156

7257
// builtin_ascii
7358

74-
fn builtin_bin(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
75-
arg_check!(vm, args, required = [(number, Some(vm.ctx.int_type()))]);
76-
77-
let n = objint::get_value(number);
78-
let s = if n.is_negative() {
79-
format!("-0b{:b}", n.abs())
59+
fn builtin_bin(x: PyIntRef, _vm: &VirtualMachine) -> String {
60+
let x = x.as_bigint();
61+
if x.is_negative() {
62+
format!("-0b{:b}", x.abs())
8063
} else {
81-
format!("0b{:b}", n)
82-
};
83-
84-
Ok(vm.new_str(s))
64+
format!("0b{:b}", x)
65+
}
8566
}
8667

8768
// builtin_breakpoint
8869

89-
fn builtin_callable(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
90-
arg_check!(vm, args, required = [(obj, None)]);
91-
let is_callable = objtype::class_has_attr(&obj.type_pyref(), "__call__");
92-
Ok(vm.new_bool(is_callable))
70+
fn builtin_callable(obj: PyObjectRef, _vm: &VirtualMachine) -> bool {
71+
objtype::class_has_attr(&obj.class(), "__call__")
9372
}
9473

95-
fn builtin_chr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
96-
arg_check!(vm, args, required = [(i, Some(vm.ctx.int_type()))]);
97-
98-
let code_point = objint::get_value(i).to_u32().unwrap();
99-
100-
let txt = match char::from_u32(code_point) {
74+
fn builtin_chr(i: u32, _vm: &VirtualMachine) -> String {
75+
match char::from_u32(i) {
10176
Some(value) => value.to_string(),
10277
None => '_'.to_string(),
103-
};
104-
105-
Ok(vm.new_str(txt))
78+
}
10679
}
10780

10881
fn builtin_compile(
@@ -135,18 +108,13 @@ fn builtin_compile(
135108
})
136109
}
137110

138-
fn builtin_delattr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
139-
arg_check!(
140-
vm,
141-
args,
142-
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
143-
);
144-
vm.del_attr(obj, attr.clone())
111+
fn builtin_delattr(obj: PyObjectRef, attr: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
112+
vm.del_attr(&obj, attr.into_object())
145113
}
146114

147115
fn builtin_dir(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
148116
if args.args.is_empty() {
149-
Ok(dir_locals(vm))
117+
Ok(vm.get_locals().into_object())
150118
} else {
151119
let obj = args.args.into_iter().next().unwrap();
152120
let seq = vm.call_method(&obj, "__dir__", vec![])?;
@@ -240,7 +208,7 @@ fn make_scope(
240208
} else if vm.isinstance(arg, &dict_type)? {
241209
Some(arg)
242210
} else {
243-
let arg_typ = arg.typ();
211+
let arg_typ = arg.class();
244212
let actual_type = vm.to_pystr(&arg_typ)?;
245213
let expected_type_name = vm.to_pystr(&dict_type)?;
246214
return Err(vm.new_type_error(format!(
@@ -254,28 +222,37 @@ fn make_scope(
254222

255223
let current_scope = vm.current_scope();
256224
let globals = match globals {
257-
Some(dict) => dict.clone(),
225+
Some(dict) => dict.clone().downcast().unwrap(),
258226
None => current_scope.globals.clone(),
259227
};
260228
let locals = match locals {
261-
Some(dict) => Some(dict.clone()),
229+
Some(dict) => dict.clone().downcast().ok(),
262230
None => current_scope.get_only_locals(),
263231
};
264232

265233
Ok(Scope::new(locals, globals))
266234
}
267235

268-
fn builtin_format(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
269-
arg_check!(
270-
vm,
271-
args,
272-
required = [(obj, None)],
273-
optional = [(format_spec, Some(vm.ctx.str_type()))]
274-
);
275-
let format_spec = format_spec
276-
.cloned()
277-
.unwrap_or_else(|| vm.new_str("".to_string()));
278-
vm.call_method(obj, "__format__", vec![format_spec])
236+
fn builtin_format(
237+
value: PyObjectRef,
238+
format_spec: OptionalArg<PyStringRef>,
239+
vm: &VirtualMachine,
240+
) -> PyResult<PyStringRef> {
241+
let format_spec = format_spec.into_option().unwrap_or_else(|| {
242+
PyString {
243+
value: "".to_string(),
244+
}
245+
.into_ref(vm)
246+
});
247+
248+
vm.call_method(&value, "__format__", vec![format_spec.into_object()])?
249+
.downcast()
250+
.map_err(|obj| {
251+
vm.new_type_error(format!(
252+
"__format__ must return a str, not {}",
253+
obj.class().name
254+
))
255+
})
279256
}
280257

281258
fn catch_attr_exception<T>(ex: PyObjectRef, default: T, vm: &VirtualMachine) -> PyResult<T> {
@@ -300,7 +277,7 @@ fn builtin_getattr(
300277
}
301278
}
302279

303-
fn builtin_globals(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
280+
fn builtin_globals(vm: &VirtualMachine) -> PyResult<PyDictRef> {
304281
Ok(vm.current_scope().globals.clone())
305282
}
306283

@@ -368,15 +345,14 @@ fn builtin_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
368345
Ok(value) => vm.invoke(value, PyFuncArgs::default()),
369346
Err(..) => Err(vm.new_type_error(format!(
370347
"object of type '{}' has no method {:?}",
371-
objtype::get_type_name(&obj.typ()),
348+
obj.class().name,
372349
len_method_name
373350
))),
374351
}
375352
}
376353

377-
fn builtin_locals(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
378-
arg_check!(vm, args);
379-
Ok(vm.get_locals())
354+
fn builtin_locals(vm: &VirtualMachine) -> PyDictRef {
355+
vm.get_locals()
380356
}
381357

382358
fn builtin_max(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -608,10 +584,9 @@ fn builtin_reversed(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
608584
match vm.get_method(obj.clone(), "__reversed__") {
609585
Ok(value) => vm.invoke(value, PyFuncArgs::default()),
610586
// TODO: fallback to using __len__ and __getitem__, if object supports sequence protocol
611-
Err(..) => Err(vm.new_type_error(format!(
612-
"'{}' object is not reversible",
613-
objtype::get_type_name(&obj.typ()),
614-
))),
587+
Err(..) => {
588+
Err(vm.new_type_error(format!("'{}' object is not reversible", obj.class().name)))
589+
}
615590
}
616591
}
617592
// builtin_reversed
@@ -656,14 +631,11 @@ fn builtin_sorted(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
656631
Ok(lst)
657632
}
658633

659-
fn builtin_sum(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
660-
arg_check!(vm, args, required = [(iterable, None)]);
661-
let items = vm.extract_elements(iterable)?;
662-
634+
fn builtin_sum(iterable: PyIterable, start: OptionalArg, vm: &VirtualMachine) -> PyResult {
663635
// Start with zero and add at will:
664-
let mut sum = vm.ctx.new_int(0);
665-
for item in items {
666-
sum = vm._add(sum, item)?;
636+
let mut sum = start.into_option().unwrap_or_else(|| vm.ctx.new_int(0));
637+
for item in iterable.iter(vm)? {
638+
sum = vm._add(sum, item?)?;
667639
}
668640
Ok(sum)
669641
}
@@ -805,9 +777,9 @@ pub fn builtin_build_class_(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResu
805777
};
806778

807779
for base in bases.clone() {
808-
if objtype::issubclass(&base.type_pyref(), &metaclass) {
809-
metaclass = base.type_pyref();
810-
} else if !objtype::issubclass(&metaclass, &base.type_pyref()) {
780+
if objtype::issubclass(&base.class(), &metaclass) {
781+
metaclass = base.class();
782+
} else if !objtype::issubclass(&metaclass, &base.class()) {
811783
return Err(vm.new_type_error("metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases".to_string()));
812784
}
813785
}
@@ -818,13 +790,15 @@ pub fn builtin_build_class_(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResu
818790
let prepare = vm.get_attribute(metaclass.clone().into_object(), "__prepare__")?;
819791
let namespace = vm.invoke(prepare, vec![name_arg.clone(), bases.clone()])?;
820792

793+
let namespace: PyDictRef = TryFromObject::try_from_object(vm, namespace)?;
794+
821795
let cells = vm.ctx.new_dict();
822796

823-
vm.invoke_with_locals(function, cells.clone().into_object(), namespace.clone())?;
797+
vm.invoke_with_locals(function, cells.clone(), namespace.clone())?;
824798
let class = vm.call_method(
825799
metaclass.as_object(),
826800
"__call__",
827-
vec![name_arg, bases, namespace],
801+
vec![name_arg, bases, namespace.into_object()],
828802
)?;
829803
cells.set_item(&vm.ctx, "__class__", class.clone());
830804
Ok(class)

vm/src/exceptions.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ fn exception_str(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
6868
args,
6969
required = [(exc, Some(vm.ctx.exceptions.exception_type.clone()))]
7070
);
71-
let type_name = objtype::get_type_name(&exc.typ());
7271
let msg = if let Ok(m) = vm.get_attribute(exc.clone(), "msg") {
7372
match vm.to_pystr(&m) {
7473
Ok(msg) => msg,
@@ -77,7 +76,7 @@ fn exception_str(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
7776
} else {
7877
panic!("Error message must be set");
7978
};
80-
let s = format!("{}: {}", type_name, msg);
79+
let s = format!("{}: {}", exc.class().name, msg);
8180
Ok(vm.new_str(s))
8281
}
8382

0 commit comments

Comments
 (0)