Skip to content

Commit

Permalink
Added Symbol.toStringTag Generation
Browse files Browse the repository at this point in the history
Re-added Class Name Attribute
Fixed Rest<T> Argument Count
  • Loading branch information
Redfire75369 committed Jan 15, 2024
1 parent fd62fb9 commit 7572f0d
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 84 deletions.
51 changes: 7 additions & 44 deletions ion-proc/src/attribute/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,21 @@

use syn::{LitStr, Result};
use syn::meta::ParseNestedMeta;
use syn::parse::{Parse, ParseStream};

use crate::attribute::{ArgumentError, ParseArgument, ParseArgumentWith, ParseAttribute};
use crate::attribute::name::Name;
use crate::class::method::MethodKind;

mod keywords {
custom_keyword!(name);
custom_keyword!(class);
}

#[allow(dead_code)]
pub(crate) struct ClassNameAttribute {
_kw: keywords::name,
_eq: Token![=],
pub(crate) name: LitStr,
}

impl Parse for ClassNameAttribute {
fn parse(input: ParseStream) -> Result<ClassNameAttribute> {
let lookahead = input.lookahead1();
if lookahead.peek(keywords::name) {
Ok(ClassNameAttribute {
_kw: input.parse()?,
_eq: input.parse()?,
name: input.parse()?,
})
} else {
Err(lookahead.error())
}
}
}

// TODO: Add `inspectable` to provide `toString` and `toJSON`
#[allow(dead_code)]
pub(crate) enum ClassAttribute {
Name(ClassNameAttribute),
Class(keywords::class),
#[derive(Default)]
pub(crate) struct ClassAttribute {
pub(crate) name: Option<LitStr>,
}

impl Parse for ClassAttribute {
fn parse(input: ParseStream) -> Result<ClassAttribute> {
use ClassAttribute as CA;

let lookahead = input.lookahead1();
if lookahead.peek(keywords::name) {
Ok(CA::Name(input.parse()?))
} else if lookahead.peek(keywords::class) {
Ok(CA::Class(input.parse()?))
} else {
Err(lookahead.error())
}
impl ParseAttribute for ClassAttribute {
fn parse(&mut self, meta: &ParseNestedMeta) -> Result<()> {
self.name.parse_argument(meta, "name", "Class")?;
Ok(())
}
}

Expand Down
9 changes: 8 additions & 1 deletion ion-proc/src/class/impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::attribute::ParseAttribute;
use crate::class::accessor::{get_accessor_name, impl_accessor, insert_accessor};
use crate::class::constructor::impl_constructor;
use crate::class::method::{impl_method, Method, MethodKind, MethodReceiver};
use crate::class::property::Property;
use crate::class::property::{Property, PropertyType};
use crate::class::r#impl::spec::PrototypeSpecs;

mod spec;
Expand Down Expand Up @@ -71,6 +71,13 @@ pub(super) fn impl_js_class_impl(r#impl: &mut ItemImpl) -> Result<[ItemImpl; 2]>
_ => (),
}
}
specs.properties.0.push(Property {
ty: PropertyType::String,
ident: parse_quote!(__ION_TO_STRING_TAG),
names: vec![Name::Symbol(
parse_quote!(#ion::symbol::WellKnownSymbolCode::ToStringTag),
)],
});

let constructor = match constructor {
Some(constructor) => constructor,
Expand Down
66 changes: 28 additions & 38 deletions ion-proc/src/class/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
*/

use proc_macro2::{Ident, Span, TokenStream};
use syn::{Error, Fields, ImplItemFn, ItemImpl, ItemStruct, Member, parse2, Path, Result, Type};
use syn::{Error, ImplItemFn, ItemImpl, ItemStruct, Member, parse2, Path, Result, Type};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;

use crate::attribute::class::ClassAttribute;
use crate::attribute::krate::crate_from_attributes;
use crate::attribute::ParseAttribute;
use crate::utils::{new_token, path_ends_with};

pub(super) fn impl_js_class_struct(r#struct: &mut ItemStruct) -> Result<[ItemImpl; 6]> {
Expand Down Expand Up @@ -40,39 +42,32 @@ pub(super) fn impl_js_class_struct(r#struct: &mut ItemStruct) -> Result<[ItemImp
r#struct.attrs.push(parse_quote!(#[derive(#ion::Traceable)]));
}

let attribute = ClassAttribute::from_attributes_mut("ion", &mut r#struct.attrs)?;

if !r#struct.generics.params.is_empty() {
return Err(Error::new(
r#struct.generics.span(),
"Native Class Structs cannot have generics.",
));
}

let name = if let Some(name) = attribute.name {
name.value()
} else {
r#struct.ident.to_string()
};

let ident = &r#struct.ident;
let r#type: Type = parse2(quote_spanned!(ident.span() => #ident))?;
let super_field;
let super_type;

let err = Err(Error::new(
r#struct.span(),
"Native Class Structs must have at least a reflector field.",
));
match &r#struct.fields {
Fields::Named(fields) => match fields.named.first() {
Some(field) => {
super_field = Member::Named(field.ident.as_ref().unwrap().clone());
super_type = field.ty.clone();
}
None => return err,
},
Fields::Unnamed(fields) => match fields.unnamed.first() {
Some(field) => {
super_field = parse_quote!(0);
super_type = field.ty.clone()
}
None => return err,
},
Fields::Unit => return err,
}

let (super_field, super_type) = if let Some(field) = r#struct.fields.iter().next() {
(Member::Named(field.ident.as_ref().unwrap().clone()), field.ty.clone())
} else {
return Err(Error::new(
r#struct.span(),
"Native Class Structs must have at least a reflector field.",
));
};

if let Type::Path(ty) = &super_type {
if ty.path.segments.iter().any(|segment| !segment.arguments.is_empty()) {
Expand All @@ -82,14 +77,7 @@ pub(super) fn impl_js_class_struct(r#struct: &mut ItemStruct) -> Result<[ItemImp
return Err(Error::new(super_type.span(), "Superclass Type must be a path."));
}

class_impls(
ion,
r#struct.span(),
&ident.to_string(),
&r#type,
&super_field,
&super_type,
)
class_impls(ion, r#struct.span(), &name, &r#type, &super_field, &super_type)
}

fn class_impls(
Expand All @@ -113,7 +101,7 @@ fn class_impls(
let operations = class_operations(span)?;
let name = format!("{}\0", name);

let mut operations_native_class: ItemImpl = parse2(quote_spanned!(span => impl #r#type {
let mut class_impl: ItemImpl = parse2(quote_spanned!(span => impl #r#type {
#(#operations)*

pub const fn __ion_native_prototype_chain() -> #ion::class::PrototypeChain {
Expand Down Expand Up @@ -149,16 +137,18 @@ fn class_impls(

&ION_NATIVE_CLASS
}

pub const __ION_TO_STRING_TAG: &'static str = #name;
}))?;
operations_native_class.attrs.push(parse_quote!(#[doc(hidden)]));
class_impl.attrs.push(parse_quote!(#[doc(hidden)]));

Ok([
from_value,
from_value_mut,
derived_from,
castable,
native_object,
operations_native_class,
class_impl,
])
}

Expand All @@ -181,7 +171,7 @@ fn impl_from_value(ion: &TokenStream, span: Span, r#type: &Type, mutable: bool)
)
}

fn class_operations(span: Span) -> Result<Vec<ImplItemFn>> {
fn class_operations(span: Span) -> Result<[ImplItemFn; 2]> {
let finalise = parse2(
quote_spanned!(span => unsafe extern "C" fn __ion_finalise_operation(_: *mut ::mozjs::jsapi::GCContext, this: *mut ::mozjs::jsapi::JSObject) {
let mut value = ::mozjs::jsval::NullValue();
Expand Down Expand Up @@ -212,5 +202,5 @@ fn class_operations(span: Span) -> Result<Vec<ImplItemFn>> {
),
)?;

Ok(vec![finalise, trace])
Ok([finalise, trace])
}
2 changes: 1 addition & 1 deletion ion-proc/src/function/parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl Parameters {
Err(e) => return Some(Err(e)),
};
if let Type::Path(ty) = &*param.pat_ty.ty {
if !path_ends_with(&ty.path, "Opt") {
if !path_ends_with(&ty.path, "Opt") && !path_ends_with(&ty.path, "Rest") {
nargs += 1;
}
}
Expand Down

0 comments on commit 7572f0d

Please sign in to comment.