Skip to content

Commit

Permalink
feat(macros): Maintain the high-level function in the scope
Browse files Browse the repository at this point in the history
  • Loading branch information
GrayJack committed Dec 4, 2024
1 parent c2eb4da commit 24699c3
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 27 deletions.
2 changes: 1 addition & 1 deletion examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn main() -> Result<(), Error> {

client.run("(print `Hello from Janet!`)")?;

client.add_c_fn(CFunOptions::new(c"testing", testing));
client.add_c_fn(CFunOptions::new(c"testing", testing_c));

// let out = client.run("(+ 2 2)")?;

Expand Down
47 changes: 32 additions & 15 deletions janetrs_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use utils::{Arg, Args, ArityArgs, JanetVersionArgs, janet_path_checker};

use crate::utils::ModArgs;

/// Macro that tranforms a high-level Janet function (`fn(&mut [Janet]) -> Janet`)
/// to the thing the Janet C API is expecting (`fn(i32, *mut janetrs::lowlevel::Janet) ->
/// janetrs::lowlevel::Janet`)
/// Macro that creates from a high-level Janet function (`fn(&mut [Janet]) -> Janet`)
/// to the kind of function the Janet C API is expecting (`fn(i32, *mut
/// janetrs::lowlevel::Janet) -> janetrs::lowlevel::Janet`) with a modified name with `_c`
/// postfix.
///
/// The optional argument `catch` adds code to catch Rust panics and transform them to
/// Janet panics. This argument is ignored if the `std` feature is deactivated.
Expand Down Expand Up @@ -113,6 +114,11 @@ pub fn janet_fn(args: TokenStream, input: TokenStream) -> TokenStream {
let doc_str = utils::get_doc(attrs.as_ref());
let vis = f.vis;
let name = f.sig.ident;
let name_c_fn = {
let mut name_c_fn = name.to_string();
name_c_fn.push_str("_c");
syn::Ident::new(&name_c_fn, name.span())
};
let name_docstring_ = {
let mut docstring = name.to_string();
docstring.push_str("_docstring_");
Expand All @@ -135,24 +141,25 @@ pub fn janet_fn(args: TokenStream, input: TokenStream) -> TokenStream {
if let syn::Type::Reference(syn::TypeReference {
mutability,
ref elem,
ref and_token,
..
}) = **ty
{
if mutability.is_none() {
return quote_spanned! {ty.span() => compile_error!("expected argument to be a mutable reference and found a immutable reference");}.into();
return quote_spanned! {and_token.span() => compile_error!("expected argument to be a mutable reference and found a immutable reference");}.into();
} else if let syn::Type::Slice(syn::TypeSlice {
elem: ref slice, ..
}) = **elem
{
if let syn::Type::Path(syn::TypePath { ref path, .. }) = **slice {
if !janet_path_checker(path) {
return quote_spanned! {path.span() => compile_error!("expected to be a `janetrs::Janet`");}.into();
return quote_spanned! {path.span() => compile_error!("expected argument to be a `janetrs::Janet`");}.into();
}
} else {
return quote_spanned! {slice.span() => compile_error!("expected to be a `janetrs::Janet`");}.into();
return quote_spanned! {slice.span() => compile_error!("expected argument to be a `janetrs::Janet`");}.into();
}
} else {
return quote_spanned! {elem.span() => compile_error!("expected to be a slice of `janetrs::Janet`");}.into();
return quote_spanned! {elem.span() => compile_error!("expected argument to be a slice of `janetrs::Janet`");}.into();
}
} else {
return quote_spanned! {ty.span() => compile_error!("expected argument to be a mutable reference and found something that is not a reference at all");}.into();
Expand All @@ -167,10 +174,10 @@ pub fn janet_fn(args: TokenStream, input: TokenStream) -> TokenStream {
if let syn::ReturnType::Type(_, ty) = f.sig.output {
if let syn::Type::Path(syn::TypePath { ref path, .. }) = *ty {
if !janet_path_checker(path) {
return quote_spanned! {output_span => compile_error!("expected return type to be `janetrs::Janet`");}.into();
return quote_spanned! {path.span() => compile_error!("expected return type to be `janetrs::Janet`");}.into();
}
} else {
return quote_spanned! {output_span => compile_error!("expected return type to be `janetrs::Janet`");}.into();
return quote_spanned! {ty.span() => compile_error!("expected return type to be `janetrs::Janet`");}.into();
}
} else {
return quote_spanned! {output_span => compile_error!("expected return type to be `janetrs::Janet`");}.into();
Expand All @@ -183,20 +190,26 @@ pub fn janet_fn(args: TokenStream, input: TokenStream) -> TokenStream {
const #name_file_: &str = ::core::concat!(::core::file!(), "\0");
#[allow(non_upper_case_globals)]
const #name_line_: u32 = ::core::line!() + 1;
#(#attrs)* #[no_mangle] #vis unsafe extern "C-unwind" fn #name(argc: i32, argv: *mut ::janetrs::lowlevel::Janet) -> ::janetrs::lowlevel::Janet {
#[inline]
#fun_clone

#(#attrs)* #[no_mangle] #vis unsafe extern "C-unwind" fn #name_c_fn(argc: i32, argv: *mut ::janetrs::lowlevel::Janet) -> ::janetrs::lowlevel::Janet {
let args = unsafe { core::slice::from_raw_parts_mut(argv, argc as usize) };
let mut args = unsafe { &mut *(args as *mut [::janetrs::lowlevel::Janet] as *mut [::janetrs::Janet])};

#(#extra)*

#name(args).into()
}
#[inline]
#fun_clone
}
} else {
quote_spanned! {f_clone.sig.inputs.span() => compile_error!("expected exactly one argument of type `&mut [janetrs::Janet]`");}
let s = {
let syn::FnArg::Typed(arg) = f_clone.sig.inputs.get(0).unwrap().clone() else {
panic!("`self` not valid here")
};

arg.pat.span()
};
quote_spanned! {s => compile_error!("expected exactly one argument of type `&mut [janetrs::Janet]`");}
}
} else {
quote_spanned! {func.span() => compile_error!("expected fn item");}
Expand Down Expand Up @@ -330,7 +343,11 @@ pub fn declare_janet_mod(input: TokenStream) -> TokenStream {

let regs_ext = fn_doc_lits.iter().enumerate().map(|(i, doc_lit)| {
let fn_name = &fn_names[i];
let fn_ptr_ident = &fn_ptr_idents[i];
let fn_ptr_ident = {
let mut name = fn_ptr_idents[i].to_string();
name.push_str("_c");
syn::Ident::new(&name, name.span())
};
let fn_doc_ident = &fn_doc_idents[i];
let fn_line_ident = &fn_line_idents[i];
let fn_file_ident = &fn_file_idents[i];
Expand Down
3 changes: 2 additions & 1 deletion janetrs_macros/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Parse for Args {

if content.len() == 2 && content[0] == content[1] {
return Err(syn::parse::Error::new(
args_span,
content[0].span(),
"repeated argument kind: There must be only one argument of each kind, that is, \
only one of `arity` or `check_mut_ref`",
));
Expand Down Expand Up @@ -397,6 +397,7 @@ impl Parse for JanetVersionArgs {
if args.len() > 2 {
let span = args
.iter()
.skip(2)
.map(|a| a.span())
.reduce(|a, other| a.join(other).unwrap_or(other))
.unwrap();
Expand Down
8 changes: 4 additions & 4 deletions janetrs_macros/tests/01-paths.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ error: expected return type to be `janetrs::Janet`
7 | pub fn function(_args: &mut [Janet]) -> Janets {
| ^^^^^^

error: expected to be a `janetrs::Janet`
error: expected argument to be a `janetrs::Janet`
--> tests/01-paths:12:31
|
12 | pub fn function2(_args: &mut [tips::Janet]) -> types::Janet {
| ^^^^
| ^^^^^^^^^^^

error: expected to be a `janetrs::Janet`
error: expected argument to be a `janetrs::Janet`
--> tests/01-paths:17:31
|
17 | pub fn function3(_args: &mut [types::Janet]) {}
| ^^^^^
| ^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion janetrs_macros/tests/02-not-function.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: expected fn item
--> tests/02-not-function:4:1
|
4 | struct A(i32);
| ^^^^^^
| ^^^^^^^^^^^^^^
4 changes: 2 additions & 2 deletions janetrs_macros/tests/06-not-slice.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected to be a slice of `janetrs::Janet`
--> $DIR/06-not-slice:7:29
error: expected argument to be a slice of `janetrs::Janet`
--> tests/06-not-slice:7:29
|
7 | pub fn function(_args: &mut Janet) -> Janet {
| ^^^^^
6 changes: 3 additions & 3 deletions janetrs_macros/tests/07-mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub fn string(_args: &mut [Janet]) -> Janet {
}

janet_mod!("rust";
{"hello", rust_hello, "(rust/hello)\n\nRust say hello"},
{"string", string, "(rust/string\n\nReturn a string"},
{"hello", rust_hello_c, "(rust/hello)\n\nRust say hello"},
{"string", string_c, "(rust/string\n\nReturn a string"},
);

fn main() {}
fn main() {}

0 comments on commit 24699c3

Please sign in to comment.