Skip to content

Commit

Permalink
Allow specifying return value from signal handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
duvholt committed Nov 30, 2020
1 parent 1c93775 commit 620ca4f
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 4 deletions.
2 changes: 2 additions & 0 deletions macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum Attribute {
async_keyword: Option<Token>,
args: Tokens,
body: Tokens,
and_return: Option<Tokens>,
},
}

Expand Down Expand Up @@ -73,6 +74,7 @@ impl Debug for Attribute {
async_keyword,
args,
body,
and_return: _,
} => {
let args: Vec<String> = args.iter().map(stringify_attr_value).collect();
let attrs: Vec<String> = body.iter().map(stringify_attr_value).collect();
Expand Down
7 changes: 5 additions & 2 deletions macros/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern {
"!" => Token::Punct1('!', _),
"on" => Token::Keyword(lexer::Keyword::On, _),
"async" => Token::Keyword(lexer::Keyword::Async, _),
"and_return" => Token::Keyword(lexer::Keyword::AndReturn, _),
"==" => Token::Punct2('=', '=', _, _),
"!=" => Token::Punct2('!', '=', _, _),
"<=" => Token::Punct2('<', '=', _, _),
Expand Down Expand Up @@ -212,9 +213,11 @@ Property: Attribute = <child_qual:"@"?> <path:(Ident "::")*> <name:Ident> "=" <v
}
};

Handler: Attribute = "on" <name:Ident> "=" <async_keyword:"async"?> <args:ClosureArgs> <body:RustExpr> => {
HackyReturn: Tokens = "and_return" "=" <value:RustExpr> => value;

Handler: Attribute = "on" <name:Ident> "=" <async_keyword:"async"?> <args:ClosureArgs> <body:RustExpr> <and_return:HackyReturn?> => {
Attribute::Handler {
name, async_keyword, args, body
name, async_keyword, args, body, and_return
}
};

Expand Down
21 changes: 20 additions & 1 deletion macros/src/gtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ pub fn expand_component(gtk: &GtkComponent) -> TokenStream {
async_keyword,
args,
body,
and_return,
} => {
if let Some(async_keyword) = async_keyword {
return quote_spanned! {async_keyword.span() =>
compile_error! { "component callbacks cannot be async" }
};
}
if let Some(and_return) = and_return {
return quote_spanned! { and_return.first().expect("and_return is empty!").span() =>
compile_error! { "cannot specify return value for component callbacks" }
}
}
let name = Ident::new(&format!("on_{}", name.to_string()), name.span());
let args = to_stream(args);
let body = to_stream(body);
Expand Down Expand Up @@ -152,7 +158,8 @@ pub fn expand_widget(gtk: &GtkWidget) -> TokenStream {
async_keyword,
args,
body,
} => expand_handler(&gtk.name, &name, async_keyword.as_ref(), &args, &body),
and_return,
} => expand_handler(&gtk.name, &name, async_keyword.as_ref(), &args, &body, and_return.as_deref()),
});
}
for child in &gtk.children {
Expand Down Expand Up @@ -262,6 +269,7 @@ pub fn expand_handler(
async_keyword: Option<&Token>,
args: &[Token],
body: &[Token],
and_return: Option<&[Token]>,
) -> TokenStream {
let object_type = to_stream(object_type);
let args_s = to_stream(args);
Expand All @@ -270,20 +278,31 @@ pub fn expand_handler(
let signal_name = to_string_literal(name);
let location = args.first().expect("signal handler is empty!").span();
let signal_id = to_string_literal(format!("{:?}", location));
let return_value = match and_return {
Some(return_args) => {
let val = to_stream(return_args);
quote! {
return #val;
}
},
None => TokenStream::new()
};
let inner_block = if async_keyword.is_some() {
quote!({
let scope = scope.clone();
vgtk::lib::glib::MainContext::ref_thread_default().spawn_local(
async move {
let msg = async move { #body_s }.await;
scope.send_message(msg);
#return_value
}
)
})
} else {
quote!({
let msg = { #body_s };
scope.send_message(msg);
#return_value
})
};
quote!(
Expand Down
2 changes: 2 additions & 0 deletions macros/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ pub type Spanned<Tok, Loc, Error> = Result<(Loc, Tok, Loc), Error>;
pub enum Keyword {
Async,
On,
AndReturn
}

fn keywordise(token: Token) -> Token {
match token {
Token::Ident(ident) => match ident.to_string().as_str() {
"async" => Token::Keyword(Keyword::Async, ident),
"on" => Token::Keyword(Keyword::On, ident),
"and_return" => Token::Keyword(Keyword::AndReturn, ident),
_ => Token::Ident(ident),
},
_ => token,
Expand Down
2 changes: 1 addition & 1 deletion vgtk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ gio = "0.9.0"
glib = "0.10.0"
gdk = "0.13.0"
gdk-pixbuf = "0.9.0"
vgtk-macros = "0.3.0"
vgtk-macros = { path = "../macros" }
proc-macro-hack = "0.5.16"
proc-macro-nested = "0.1.6"
log = "0.4.8"
Expand Down

0 comments on commit 620ca4f

Please sign in to comment.