Skip to content

Commit

Permalink
Fixed Headers Implementation According to Specification
Browse files Browse the repository at this point in the history
Improved Class Definition Trait Methods
Modified This Parameter Handling in Native Functions
  • Loading branch information
Redfire75369 committed Oct 19, 2023
1 parent 116151c commit 289b656
Show file tree
Hide file tree
Showing 20 changed files with 515 additions and 243 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ion-proc/src/class/accessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Accessor {

let setter = parse2(quote!(
fn #setter_ident(#[ion(this)] this: &mut #ion::Object, #[ion(convert = #convert)] #ident: #ty) -> #ion::Result<()> {
let self_ = <#class_ty as #ion::ClassDefinition>::get_private(this);
let self_ = <#class_ty as #ion::ClassDefinition>::get_mut_private(this);
self_.#ident = #ident;
Ok(())
}
Expand Down Expand Up @@ -192,7 +192,7 @@ pub(crate) fn impl_accessor(crates: &Crates, method: &ItemFn, ty: &Type, keep_in
let error = Error::new_spanned(&method.sig, error_message);

let (accessor, parameters) = impl_method(crates, method.clone(), ty, keep_inner, |sig| {
let parameters = Parameters::parse(&sig.inputs, Some(ty), false)?;
let parameters = Parameters::parse(&sig.inputs, Some(ty))?;
let nargs = parameters.parameters.iter().fold(0, |mut acc, param| {
if let Parameter::Regular { ty, .. } = &param {
if let Type::Path(_) = &**ty {
Expand Down
5 changes: 2 additions & 3 deletions ion-proc/src/class/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) fn impl_method<F>(crates: &Crates, mut method: ItemFn, ty: &Type, kee
where
F: FnOnce(&Signature) -> Result<()>,
{
let (wrapper, mut inner, parameters) = impl_wrapper_fn(crates, method.clone(), Some(ty), keep_inner, true)?;
let (wrapper, mut inner, parameters) = impl_wrapper_fn(crates, method.clone(), Some(ty), keep_inner, false)?;
let ion = &crates.ion;

predicate(&method.sig).and_then(|_| {
Expand All @@ -55,11 +55,10 @@ where
let body = parse_quote!({
let cx = &#ion::Context::new_unchecked(cx);
let args = &mut #ion::Arguments::new(cx, argc, vp);
let mut this = args.access().this().to_object(cx);

#wrapper

let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| wrapper(cx, args, &mut this)));
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| wrapper(cx, args)));
#ion::functions::__handle_native_function_result(cx, result, args.rval())
});
method.block = Box::new(body);
Expand Down
2 changes: 1 addition & 1 deletion ion-proc/src/class/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

use std::collections::HashMap;
use either::Either;

use either::Either;
use quote::ToTokens;
use syn::{Error, ImplItem, Item, ItemFn, ItemImpl, ItemMod, LitStr, Meta, parse2, Result, Visibility};
use syn::punctuated::Punctuated;
Expand Down
145 changes: 75 additions & 70 deletions ion-proc/src/function/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ use crate::attribute::function::ParameterAttribute;
use crate::utils::{format_pat, type_ends_with};
use crate::visitors::{LifetimeRemover, SelfRenamer};

#[derive(Clone, Debug, PartialEq)]
pub(crate) enum ThisKind {
Ref(Option<Lifetime>, Option<Token![mut]>),
Owned,
}

#[derive(Debug)]
pub(crate) enum Parameter {
Regular {
Expand All @@ -39,7 +33,13 @@ pub(crate) enum Parameter {
},
Context(Box<Pat>, Box<Type>),
Arguments(Box<Pat>, Box<Type>),
This(Box<Pat>, Box<Type>),
}

#[derive(Clone, Debug, PartialEq)]
pub(crate) enum ThisKind {
Ref(Option<Lifetime>, Option<Token![mut]>),
Object(Option<Lifetime>, Option<Token![mut]>),
Owned,
}

#[derive(Debug)]
Expand All @@ -57,7 +57,7 @@ pub(crate) struct Parameters {
}

impl Parameter {
pub(crate) fn from_arg(arg: &FnArg, is_class: bool) -> Result<Parameter> {
pub(crate) fn from_arg(arg: &FnArg) -> Result<Parameter> {
match arg {
FnArg::Typed(pat_ty) => {
let PatType { pat, ty, .. } = pat_ty.clone();
Expand Down Expand Up @@ -94,9 +94,6 @@ impl Parameter {
PA::Strict(_) => {
strict = true;
}
PA::This(_) if is_class => {
return Ok(Parameter::This(pat, ty));
}
_ => (),
}
}
Expand Down Expand Up @@ -128,10 +125,9 @@ impl Parameter {

pub(crate) fn get_type_without_lifetimes(&self) -> Type {
use Parameter as P;
let (P::Regular { ty, .. } | P::VarArgs { ty, .. } | P::Context(_, ty) | P::Arguments(_, ty) | P::This(_, ty)) = self;
let (P::Regular { ty, .. } | P::VarArgs { ty, .. } | P::Context(_, ty) | P::Arguments(_, ty)) = self;
let mut ty = *ty.clone();
let mut lifetime_remover = LifetimeRemover;
visit_type_mut(&mut lifetime_remover, &mut ty);
visit_type_mut(&mut LifetimeRemover, &mut ty);
ty
}

Expand All @@ -143,36 +139,28 @@ impl Parameter {
P::VarArgs { pat, conversion, strict, .. } => varargs_param_statement(pat, &ty, conversion, *strict),
P::Context(pat, _) => parse2(quote!(let #pat: #ty = __cx;)),
P::Arguments(pat, _) => parse2(quote!(let #pat: #ty = __args;)),
P::This(pat, _) => parse2(quote!(let #pat: #ty = __this;)),
}
}
}

impl ThisParameter {
pub(crate) fn from_arg(arg: &FnArg, class_ty: Option<&Type>, is_class: bool) -> Result<Option<ThisParameter>> {
pub(crate) fn from_arg(arg: &FnArg, class_ty: Option<&Type>) -> Result<Option<ThisParameter>> {
match arg {
FnArg::Typed(pat_ty) => {
let span = pat_ty.span();
let PatType { pat, ty, .. } = pat_ty.clone();
let PatType { pat, mut ty, .. } = pat_ty.clone();
match class_ty {
Some(class_ty) if pat == parse_quote!(self) => {
let class_ty = Box::new(class_ty.clone());
let mut self_renamer = SelfRenamer { ty: class_ty };
let mut ty = ty;
visit_type_mut(&mut self_renamer, &mut ty);
visit_type_mut(&mut SelfRenamer { ty: class_ty }, &mut ty);
parse_this(pat, ty, true, span).map(Some)
}
_ => {
if !is_class {
for attr in &pat_ty.attrs {
if attr.path().is_ident("ion") {
let args: Punctuated<ParameterAttribute, Token![,]> = attr.parse_args_with(Punctuated::parse_terminated)?;

use ParameterAttribute as PA;
for arg in args {
if let PA::This(_) = arg {
return parse_this(pat, ty, class_ty.is_some(), span).map(Some);
}
for attr in &pat_ty.attrs {
if attr.path().is_ident("ion") {
let args: Punctuated<ParameterAttribute, Token![,]> = attr.parse_args_with(Punctuated::parse_terminated)?;
for arg in args {
if let ParameterAttribute::This(_) = arg {
return parse_this(pat, ty, class_ty.is_some(), span).map(Some);
}
}
}
Expand Down Expand Up @@ -203,55 +191,69 @@ impl ThisParameter {

pub(crate) fn to_statement(&self, ion: &TokenStream, is_class: bool) -> Result<Stmt> {
let ThisParameter { pat, ty, kind } = self;
if is_class {
let pat = if **pat == parse_quote!(self) { parse_quote!(self_) } else { pat.clone() };
match kind {
ThisKind::Ref(lt, mutability) => parse2(quote!(
let #pat: &#lt #mutability #ty = <#ty as #ion::ClassDefinition>::get_private(__this);
)),
ThisKind::Owned => Err(Error::new(pat.span(), "Self cannot be owned on Class Methods")),
let self_ = parse_quote!(self_);
let pat = if is_class && &**pat == &parse_quote!(self) { &self_ } else { pat };
let mut ty = ty.clone();
visit_type_mut(&mut LifetimeRemover, &mut ty);

match kind {
ThisKind::Ref(lt, mutability) => {
if is_class {
parse2(quote!(
let #pat: &#lt #mutability #ty = <#ty as #ion::ClassDefinition>::get_mut_private(__this);
))
} else {
parse2(quote!(
let #pat: #ty = <#ty as #ion::conversions::FromValue>::from_value(__cx, __accessor.this(), true, ())?;
))
}
}
} else {
parse2(quote!(let #pat: #ty = <#ty as #ion::conversions::FromValue>::from_value(__cx, __accessor.this(), true, ())?;))
ThisKind::Object(_, mutability) => parse2(quote!(let #pat: &#mutability #ty = __this;)),
ThisKind::Owned => Err(Error::new(pat.span(), "This cannot be owned")),
}
}

pub(crate) fn to_async_class_statement(&self, ion: &TokenStream) -> Result<Stmt> {
let ThisParameter { pat, ty, kind } = self;

let pat = if **pat == parse_quote!(self) { parse_quote!(self_) } else { pat.clone() };
let mut ty = ty.clone();
visit_type_mut(&mut LifetimeRemover, &mut ty);

match kind {
ThisKind::Ref(_, mutability) => {
parse2(quote!(let #pat: &'static #mutability #ty = &mut *(<#ty as #ion::ClassDefinition>::get_private(&__this) as *mut #ty);))
}
ThisKind::Owned => Err(Error::new(pat.span(), "Self cannot be owned on Class Methods")),
ThisKind::Ref(_, mutability) => parse2(quote!(
let #pat: &'static #mutability #ty = &mut *(<#ty as #ion::ClassDefinition>::get_mut_private(&mut __this) as *mut #ty);
)),
ThisKind::Object(_, mutability) => parse2(quote!(let #pat: &#mutability #ty = __this;)),
ThisKind::Owned => Err(Error::new(pat.span(), "This cannot be owned")),
}
}
}

impl Parameters {
pub(crate) fn parse(parameters: &Punctuated<FnArg, Token![,]>, ty: Option<&Type>, is_class: bool) -> Result<Parameters> {
pub(crate) fn parse(parameters: &Punctuated<FnArg, Token![,]>, ty: Option<&Type>) -> Result<Parameters> {
let mut nargs = (0, 0);
let mut this = None;
let mut this: Option<(ThisParameter, Ident, usize)> = None;
let mut idents = Vec::new();

let parameters: Vec<_> = parameters
.iter()
.enumerate()
.filter_map(|(i, arg)| {
let this_param = ThisParameter::from_arg(arg, ty, is_class);
let this_param = ThisParameter::from_arg(arg, ty);
match this_param {
Ok(Some(this_param)) => {
if let Pat::Ident(ident) = &*this_param.pat {
let ident2 = ident.ident.clone();
this = Some((this_param, ident2, i));
if let Pat::Ident(ident) = (*this_param.pat).clone() {
if let Some(this) = &this {
return Some(Err(Error::new(this.1.span(), "Unable to have multiple this/self parameters")));
}
this = Some((this_param, ident.ident.clone(), i));
}
return None;
}
Err(e) => return Some(Err(e)),
_ => (),
}
let param = Parameter::from_arg(arg, is_class);
let param = Parameter::from_arg(arg);
match param {
Ok(Parameter::Regular { pat, ty, conversion, strict, option }) => {
if option.is_none() {
Expand Down Expand Up @@ -282,12 +284,6 @@ impl Parameters {
}
Some(Ok(Parameter::Arguments(pat, ty)))
}
Ok(Parameter::This(pat, ty)) => {
if let Some(ident) = get_ident(&pat) {
idents.push(ident);
}
Some(Ok(Parameter::This(pat, ty)))
}
Err(e) => Some(Err(e)),
}
})
Expand All @@ -304,17 +300,17 @@ impl Parameters {
self.this.as_ref().map(|x| x.1.clone())
}

pub(crate) fn to_this_statements(&self, ion: &TokenStream, is_class: bool, is_async: bool) -> Result<TokenStream> {
pub(crate) fn to_this_statement(&self, ion: &TokenStream, is_class: bool, is_async: bool) -> Result<Option<TokenStream>> {
match &self.this {
Some((this, _, _)) => {
let statement = if is_class && is_async {
this.to_async_class_statement(ion)?
} else {
this.to_statement(ion, is_class)?
};
Ok(statement.to_token_stream())
Ok(Some(statement.into_token_stream()))
}
None => Ok(TokenStream::default()),
None => Ok(None),
}
}

Expand All @@ -328,9 +324,7 @@ impl Parameters {
Parameter::Regular { pat, ty, .. } | Parameter::VarArgs { pat, ty, .. } => {
parse2(quote_spanned!(pat.span() => #pat: #ty)).unwrap()
}
Parameter::Context(pat, ty) | Parameter::Arguments(pat, ty) | Parameter::This(pat, ty) => {
parse2(quote_spanned!(pat.span() => #pat: #ty)).unwrap()
}
Parameter::Context(pat, ty) | Parameter::Arguments(pat, ty) => parse2(quote_spanned!(pat.span() => #pat: #ty)).unwrap(),
})
.collect::<Vec<_>>(),
);
Expand All @@ -340,6 +334,7 @@ impl Parameters {
*index,
match kind {
ThisKind::Ref(lt, mutability) => parse2(quote_spanned!(pat.span() => #pat: &#lt #mutability #ty)).unwrap(),
ThisKind::Object(lt, mutability) => parse2(quote_spanned!(pat.span() => #pat: &#lt #mutability #ty)).unwrap(),
ThisKind::Owned => parse2(quote_spanned!(pat.span() => #pat: #ty)).unwrap(),
},
);
Expand Down Expand Up @@ -395,12 +390,22 @@ pub(crate) fn get_ident(pat: &Pat) -> Option<Ident> {
pub(crate) fn parse_this(pat: Box<Pat>, ty: Box<Type>, is_class: bool, span: Span) -> Result<ThisParameter> {
match *ty {
Type::Reference(reference) => {
let ty = reference.elem;
Ok(ThisParameter {
pat,
ty,
kind: ThisKind::Ref(reference.lifetime, reference.mutability),
})
let lt = reference.lifetime;
let mutability = reference.mutability;
match *reference.elem {
Type::Path(ty) if type_ends_with(&ty, "Object") => {
return Ok(ThisParameter {
pat,
ty: Box::new(Type::Path(ty)),
kind: ThisKind::Object(lt, mutability),
});
}
ty => Ok(ThisParameter {
pat,
ty: Box::new(ty),
kind: ThisKind::Ref(lt, mutability),
}),
}
}
ty if !is_class => Ok(ThisParameter {
pat,
Expand Down
Loading

0 comments on commit 289b656

Please sign in to comment.