Skip to content

Commit 18b5718

Browse files
Add a custom derive for FromArgs
1 parent 7cb889d commit 18b5718

File tree

8 files changed

+106
-51
lines changed

8 files changed

+106
-51
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/target
2+
/*/target
23
**/*.rs.bk
34
**/*.bytecode
45
__pycache__

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ authors = ["Windel Bouwman", "Shing Lyu <shing.lyu@gmail.com>"]
55
edition = "2018"
66

77
[workspace]
8-
members = [".", "vm", "wasm/lib", "parser"]
8+
members = [".", "derive", "vm", "wasm/lib", "parser"]
99

1010
[dependencies]
1111
log="0.4.1"

derive/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "rustpython_derive"
3+
version = "0.1.0"
4+
authors = ["Joey <jmhain@protonmail.com>"]
5+
edition = "2018"
6+
7+
[lib]
8+
proc-macro = true
9+
10+
[dependencies]
11+
syn = "0.15.29"
12+
quote = "0.6.11"
13+
proc-macro2 = "0.4.27"

derive/src/lib.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
extern crate proc_macro;
2+
3+
use proc_macro::TokenStream;
4+
use proc_macro2::TokenStream as TokenStream2;
5+
use quote::quote;
6+
use syn::{Data, DeriveInput, Fields};
7+
8+
#[proc_macro_derive(FromArgs)]
9+
pub fn derive_from_args(input: TokenStream) -> TokenStream {
10+
let ast: DeriveInput = syn::parse(input).unwrap();
11+
12+
let gen = impl_from_args(&ast);
13+
gen.to_string().parse().unwrap()
14+
}
15+
16+
fn impl_from_args(input: &DeriveInput) -> TokenStream2 {
17+
// FIXME: This references types using `crate` instead of `rustpython_vm`
18+
// so that it can be used in the latter. How can we support both?
19+
let fields = match input.data {
20+
Data::Struct(ref data) => {
21+
match data.fields {
22+
Fields::Named(ref fields) => fields.named.iter().map(|field| {
23+
let name = &field.ident;
24+
quote! {
25+
#name: crate::pyobject::TryFromObject::try_from_object(
26+
vm,
27+
args.take_keyword(stringify!(#name)).unwrap_or_else(|| vm.ctx.none())
28+
)?,
29+
}
30+
}),
31+
Fields::Unnamed(_) | Fields::Unit => unimplemented!(), // TODO: better error message
32+
}
33+
}
34+
Data::Enum(_) | Data::Union(_) => unimplemented!(), // TODO: better error message
35+
};
36+
37+
let name = &input.ident;
38+
quote! {
39+
impl crate::function::FromArgs for #name {
40+
fn from_args(
41+
vm: &mut crate::vm::VirtualMachine,
42+
args: &mut crate::function::PyFuncArgs
43+
) -> Result<Self, crate::function::ArgumentError> {
44+
Ok(#name { #(#fields)* })
45+
}
46+
}
47+
}
48+
}

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ num-integer = "0.1.39"
1313
num-rational = "0.2.1"
1414
rand = "0.5"
1515
log = "0.3"
16+
rustpython_derive = {path = "../derive"}
1617
rustpython_parser = {path = "../parser"}
1718
serde = "1.0.66"
1819
serde_derive = "1.0.66"

vm/src/builtins.rs

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use crate::obj::objstr::{self, PyStringRef};
1818
use crate::obj::objtype;
1919

2020
use crate::frame::Scope;
21-
use crate::function::{Args, ArgumentError, FromArgs, PyFuncArgs};
21+
use crate::function::{Args, PyFuncArgs};
2222
use crate::pyobject::{
23-
AttributeProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
23+
AttributeProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, TypeProtocol,
2424
};
2525
use crate::vm::VirtualMachine;
2626

@@ -582,33 +582,13 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
582582
}
583583
}
584584

585-
#[derive(Debug)]
585+
#[derive(Debug, FromArgs)]
586586
pub struct PrintOptions {
587587
sep: Option<PyStringRef>,
588588
end: Option<PyStringRef>,
589589
flush: bool,
590590
}
591591

592-
// In the future, this impl will be generated w/ a derive macro.
593-
impl FromArgs for PrintOptions {
594-
fn from_args(vm: &mut VirtualMachine, args: &mut PyFuncArgs) -> Result<Self, ArgumentError> {
595-
Ok(PrintOptions {
596-
sep: TryFromObject::try_from_object(
597-
vm,
598-
args.take_keyword("sep").unwrap_or_else(|| vm.ctx.none()),
599-
)?,
600-
end: TryFromObject::try_from_object(
601-
vm,
602-
args.take_keyword("end").unwrap_or_else(|| vm.ctx.none()),
603-
)?,
604-
flush: TryFromObject::try_from_object(
605-
vm,
606-
args.take_keyword("flush").unwrap_or_else(|| vm.ctx.none()),
607-
)?,
608-
})
609-
}
610-
}
611-
612592
pub fn builtin_print(
613593
objects: Args,
614594
options: PrintOptions,

vm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ extern crate serde_json;
2525
extern crate statrs;
2626

2727
extern crate rustpython_parser;
28+
#[macro_use]
29+
extern crate rustpython_derive;
2830

2931
//extern crate eval; use eval::eval::*;
3032
// use py_code_object::{Function, NativeType, PyCodeObject};

0 commit comments

Comments
 (0)