Skip to content

Commit 7f75e3e

Browse files
Significant improvements to new function definition style
- PyRef<T> type for accepting references to payloads. - Args<T> type for consuming remaining positional args (mirrors python `*args`). - KwArgs<T> type for consuming remaining keyword args (mirrors python `*kwargs`). - OptArg<T> type for consuming remaining keyword args (no python code equivalent, only possible in native functions like in cpython). - PyIterable<T> for accepting an iterator over a sequence of Ts. - Arity checking (but TypeError messages need work)
1 parent d6242ac commit 7f75e3e

File tree

6 files changed

+332
-172
lines changed

6 files changed

+332
-172
lines changed

vm/src/function.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use std::marker::PhantomData;
2+
use std::ops::Deref;
3+
4+
use crate::obj::objtype;
5+
use crate::pyobject::{PyObjectPayload2, PyObjectRef, PyResult, TryFromObject};
6+
use crate::vm::VirtualMachine;
7+
8+
// TODO: Move PyFuncArgs, FromArgs, etc. here
9+
10+
pub struct PyRef<T> {
11+
// invariant: this obj must always have payload of type T
12+
obj: PyObjectRef,
13+
_payload: PhantomData<T>,
14+
}
15+
16+
impl<T> Deref for PyRef<T>
17+
where
18+
T: PyObjectPayload2,
19+
{
20+
type Target = T;
21+
22+
fn deref(&self) -> &T {
23+
self.obj.payload().expect("unexpected payload for type")
24+
}
25+
}
26+
27+
impl<T> TryFromObject for PyRef<T>
28+
where
29+
T: PyObjectPayload2,
30+
{
31+
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
32+
if objtype::isinstance(&obj, &T::required_type(&vm.ctx)) {
33+
Ok(PyRef {
34+
obj,
35+
_payload: PhantomData,
36+
})
37+
} else {
38+
Err(vm.new_type_error("wrong type".to_string())) // TODO: better message
39+
}
40+
}
41+
}

vm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub mod eval;
3838
mod exceptions;
3939
pub mod format;
4040
mod frame;
41+
pub mod function;
4142
pub mod import;
4243
pub mod obj;
4344
pub mod pyobject;

vm/src/obj/objint.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::objtype;
44
use crate::format::FormatSpec;
55
use crate::pyobject::{
66
FromPyObjectRef, IntoPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef,
7-
PyResult, TypeProtocol,
7+
PyResult, TryFromObject, TypeProtocol,
88
};
99
use crate::vm::VirtualMachine;
1010
use num_bigint::{BigInt, ToBigInt};
@@ -31,6 +31,26 @@ impl IntoPyObject for usize {
3131
}
3232
}
3333

34+
impl TryFromObject for usize {
35+
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
36+
// FIXME: don't use get_value
37+
match get_value(&obj).to_usize() {
38+
Some(value) => Ok(value),
39+
None => Err(vm.new_overflow_error("Int value cannot fit into Rust usize".to_string())),
40+
}
41+
}
42+
}
43+
44+
impl TryFromObject for isize {
45+
fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
46+
// FIXME: don't use get_value
47+
match get_value(&obj).to_isize() {
48+
Some(value) => Ok(value),
49+
None => Err(vm.new_overflow_error("Int value cannot fit into Rust isize".to_string())),
50+
}
51+
}
52+
}
53+
3454
fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
3555
arg_check!(vm, args, required = [(int, Some(vm.ctx.int_type()))]);
3656
let v = get_value(int);

vm/src/obj/objrange.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use std::ops::Mul;
44
use super::objint;
55
use super::objtype;
66
use crate::pyobject::{
7-
FromPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
8-
TypeProtocol,
7+
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
98
};
109
use crate::vm::VirtualMachine;
1110
use num_bigint::{BigInt, Sign};
@@ -21,18 +20,6 @@ pub struct RangeType {
2120
pub step: BigInt,
2221
}
2322

24-
type PyRange = RangeType;
25-
26-
impl FromPyObject for PyRange {
27-
fn typ(ctx: &PyContext) -> Option<PyObjectRef> {
28-
Some(ctx.range_type())
29-
}
30-
31-
fn from_pyobject(obj: PyObjectRef) -> PyResult<Self> {
32-
Ok(get_value(&obj))
33-
}
34-
}
35-
3623
impl RangeType {
3724
#[inline]
3825
pub fn try_len(&self) -> Option<usize> {
@@ -360,12 +347,22 @@ fn range_bool(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
360347
Ok(vm.ctx.new_bool(len > 0))
361348
}
362349

363-
fn range_contains(vm: &mut VirtualMachine, zelf: PyRange, needle: PyObjectRef) -> bool {
364-
if objtype::isinstance(&needle, &vm.ctx.int_type()) {
365-
zelf.contains(&objint::get_value(&needle))
350+
fn range_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
351+
arg_check!(
352+
vm,
353+
args,
354+
required = [(zelf, Some(vm.ctx.range_type())), (needle, None)]
355+
);
356+
357+
let range = get_value(zelf);
358+
359+
let result = if objtype::isinstance(needle, &vm.ctx.int_type()) {
360+
range.contains(&objint::get_value(needle))
366361
} else {
367362
false
368-
}
363+
};
364+
365+
Ok(vm.ctx.new_bool(result))
369366
}
370367

371368
fn range_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

vm/src/obj/objstr.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::objsequence::PySliceableSequence;
33
use super::objtype;
44
use crate::format::{FormatParseError, FormatPart, FormatString};
55
use crate::pyobject::{
6-
FromPyObject, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
6+
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
77
};
88
use crate::vm::VirtualMachine;
99
use num_traits::ToPrimitive;
@@ -16,16 +16,6 @@ extern crate unicode_segmentation;
1616

1717
use self::unicode_segmentation::UnicodeSegmentation;
1818

19-
impl FromPyObject for String {
20-
fn typ(ctx: &PyContext) -> Option<PyObjectRef> {
21-
Some(ctx.str_type())
22-
}
23-
24-
fn from_pyobject(obj: PyObjectRef) -> PyResult<Self> {
25-
Ok(get_value(&obj))
26-
}
27-
}
28-
2919
pub fn init(context: &PyContext) {
3020
let str_type = &context.str_type;
3121
context.set_attr(&str_type, "__add__", context.new_rustfunc(str_add));
@@ -477,8 +467,15 @@ fn str_rstrip(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
477467
Ok(vm.ctx.new_str(value))
478468
}
479469

480-
fn str_endswith(_vm: &mut VirtualMachine, zelf: String, suffix: String) -> bool {
481-
zelf.ends_with(&suffix)
470+
fn str_endswith(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
471+
arg_check!(
472+
vm,
473+
args,
474+
required = [(s, Some(vm.ctx.str_type())), (pat, Some(vm.ctx.str_type()))]
475+
);
476+
let value = get_value(&s);
477+
let pat = get_value(&pat);
478+
Ok(vm.ctx.new_bool(value.ends_with(pat.as_str())))
482479
}
483480

484481
fn str_isidentifier(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

0 commit comments

Comments
 (0)