diff options
Diffstat (limited to 'macros/src/syntax/parse/util.rs')
-rw-r--r-- | macros/src/syntax/parse/util.rs | 338 |
1 files changed, 0 insertions, 338 deletions
diff --git a/macros/src/syntax/parse/util.rs b/macros/src/syntax/parse/util.rs deleted file mode 100644 index 5a5e0c0e..00000000 --- a/macros/src/syntax/parse/util.rs +++ /dev/null @@ -1,338 +0,0 @@ -use syn::{ - bracketed, - parse::{self, ParseStream}, - punctuated::Punctuated, - spanned::Spanned, - Abi, AttrStyle, Attribute, Expr, FnArg, ForeignItemFn, Ident, ItemFn, Pat, PatType, Path, - PathArguments, ReturnType, Token, Type, Visibility, -}; - -use crate::syntax::{ - ast::{Access, Local, LocalResources, SharedResources, TaskLocal}, - Map, -}; - -pub fn abi_is_rust(abi: &Abi) -> bool { - match &abi.name { - None => true, - Some(s) => s.value() == "Rust", - } -} - -pub fn attr_eq(attr: &Attribute, name: &str) -> bool { - attr.style == AttrStyle::Outer && attr.path.segments.len() == 1 && { - let segment = attr.path.segments.first().unwrap(); - segment.arguments == PathArguments::None && *segment.ident.to_string() == *name - } -} - -/// checks that a function signature -/// -/// - has no bounds (like where clauses) -/// - is not `async` -/// - is not `const` -/// - is not `unsafe` -/// - is not generic (has no type parameters) -/// - is not variadic -/// - uses the Rust ABI (and not e.g. "C") -pub fn check_fn_signature(item: &ItemFn, allow_async: bool) -> bool { - item.vis == Visibility::Inherited - && item.sig.constness.is_none() - && (item.sig.asyncness.is_none() || allow_async) - && item.sig.abi.is_none() - && item.sig.unsafety.is_none() - && item.sig.generics.params.is_empty() - && item.sig.generics.where_clause.is_none() - && item.sig.variadic.is_none() -} - -#[allow(dead_code)] -pub fn check_foreign_fn_signature(item: &ForeignItemFn, allow_async: bool) -> bool { - item.vis == Visibility::Inherited - && item.sig.constness.is_none() - && (item.sig.asyncness.is_none() || allow_async) - && item.sig.abi.is_none() - && item.sig.unsafety.is_none() - && item.sig.generics.params.is_empty() - && item.sig.generics.where_clause.is_none() - && item.sig.variadic.is_none() -} - -pub struct FilterAttrs { - pub cfgs: Vec<Attribute>, - pub docs: Vec<Attribute>, - pub attrs: Vec<Attribute>, -} - -pub fn filter_attributes(input_attrs: Vec<Attribute>) -> FilterAttrs { - let mut cfgs = vec![]; - let mut docs = vec![]; - let mut attrs = vec![]; - - for attr in input_attrs { - if attr_eq(&attr, "cfg") { - cfgs.push(attr); - } else if attr_eq(&attr, "doc") { - docs.push(attr); - } else { - attrs.push(attr); - } - } - - FilterAttrs { cfgs, docs, attrs } -} - -pub fn extract_lock_free(attrs: &mut Vec<Attribute>) -> parse::Result<bool> { - if let Some(pos) = attrs.iter().position(|attr| attr_eq(attr, "lock_free")) { - attrs.remove(pos); - Ok(true) - } else { - Ok(false) - } -} - -pub fn parse_shared_resources(content: ParseStream<'_>) -> parse::Result<SharedResources> { - let inner; - bracketed!(inner in content); - - let mut resources = Map::new(); - for e in inner.call(Punctuated::<Expr, Token![,]>::parse_terminated)? { - let err = Err(parse::Error::new( - e.span(), - "identifier appears more than once in list", - )); - let (access, path) = match e { - Expr::Path(e) => (Access::Exclusive, e.path), - - Expr::Reference(ref r) if r.mutability.is_none() => match &*r.expr { - Expr::Path(e) => (Access::Shared, e.path.clone()), - - _ => return err, - }, - - _ => return err, - }; - - let ident = extract_resource_name_ident(path)?; - - if resources.contains_key(&ident) { - return Err(parse::Error::new( - ident.span(), - "resource appears more than once in list", - )); - } - - resources.insert(ident, access); - } - - Ok(resources) -} - -fn extract_resource_name_ident(path: Path) -> parse::Result<Ident> { - if path.leading_colon.is_some() - || path.segments.len() != 1 - || path.segments[0].arguments != PathArguments::None - { - Err(parse::Error::new( - path.span(), - "resource must be an identifier, not a path", - )) - } else { - Ok(path.segments[0].ident.clone()) - } -} - -pub fn parse_local_resources(content: ParseStream<'_>) -> parse::Result<LocalResources> { - let inner; - bracketed!(inner in content); - - let mut resources = Map::new(); - - for e in inner.call(Punctuated::<Expr, Token![,]>::parse_terminated)? { - let err = Err(parse::Error::new( - e.span(), - "identifier appears more than once in list", - )); - - let (name, local) = match e { - // local = [IDENT], - Expr::Path(path) => { - if !path.attrs.is_empty() { - return Err(parse::Error::new( - path.span(), - "attributes are not supported here", - )); - } - - let ident = extract_resource_name_ident(path.path)?; - // let (cfgs, attrs) = extract_cfgs(path.attrs); - - (ident, TaskLocal::External) - } - - // local = [IDENT: TYPE = EXPR] - Expr::Assign(e) => { - let (name, ty, cfgs, attrs) = match *e.left { - Expr::Type(t) => { - // Extract name and attributes - let (name, cfgs, attrs) = match *t.expr { - Expr::Path(path) => { - let name = extract_resource_name_ident(path.path)?; - let FilterAttrs { cfgs, attrs, .. } = filter_attributes(path.attrs); - - (name, cfgs, attrs) - } - _ => return err, - }; - - let ty = t.ty; - - // Error check - match &*ty { - Type::Array(_) => {} - Type::Path(_) => {} - Type::Ptr(_) => {} - Type::Tuple(_) => {} - _ => return Err(parse::Error::new( - ty.span(), - "unsupported type, must be an array, tuple, pointer or type path", - )), - }; - - (name, ty, cfgs, attrs) - } - e => return Err(parse::Error::new(e.span(), "malformed, expected a type")), - }; - - let expr = e.right; // Expr - - ( - name, - TaskLocal::Declared(Local { - attrs, - cfgs, - ty, - expr, - }), - ) - } - - expr => { - return Err(parse::Error::new( - expr.span(), - "malformed, expected 'IDENT: TYPE = EXPR'", - )) - } - }; - - resources.insert(name, local); - } - - Ok(resources) -} - -type ParseInputResult = Option<(Box<Pat>, Result<Vec<PatType>, FnArg>)>; - -pub fn parse_inputs(inputs: Punctuated<FnArg, Token![,]>, name: &str) -> ParseInputResult { - let mut inputs = inputs.into_iter(); - - match inputs.next() { - Some(FnArg::Typed(first)) => { - if type_is_path(&first.ty, &[name, "Context"]) { - let rest = inputs - .map(|arg| match arg { - FnArg::Typed(arg) => Ok(arg), - _ => Err(arg), - }) - .collect::<Result<Vec<_>, _>>(); - - Some((first.pat, rest)) - } else { - None - } - } - - _ => None, - } -} - -pub fn type_is_bottom(ty: &ReturnType) -> bool { - if let ReturnType::Type(_, ty) = ty { - matches!(**ty, Type::Never(_)) - } else { - false - } -} - -fn extract_init_resource_name_ident(ty: Type) -> Result<Ident, ()> { - match ty { - Type::Path(path) => { - let path = path.path; - - if path.leading_colon.is_some() - || path.segments.len() != 1 - || path.segments[0].arguments != PathArguments::None - { - Err(()) - } else { - Ok(path.segments[0].ident.clone()) - } - } - _ => Err(()), - } -} - -/// Checks Init's return type, return the user provided types for analysis -pub fn type_is_init_return(ty: &ReturnType) -> Result<(Ident, Ident), ()> { - match ty { - ReturnType::Default => Err(()), - - ReturnType::Type(_, ty) => match &**ty { - Type::Tuple(t) => { - // return should be: - // fn -> (User's #[shared] struct, User's #[local] struct) - // - // We check the length and the last one here, analysis checks that the user - // provided structs are correct. - if t.elems.len() == 2 { - return Ok(( - extract_init_resource_name_ident(t.elems[0].clone())?, - extract_init_resource_name_ident(t.elems[1].clone())?, - )); - } - - Err(()) - } - - _ => Err(()), - }, - } -} - -pub fn type_is_path(ty: &Type, segments: &[&str]) -> bool { - match ty { - Type::Path(tpath) if tpath.qself.is_none() => { - tpath.path.segments.len() == segments.len() - && tpath - .path - .segments - .iter() - .zip(segments) - .all(|(lhs, rhs)| lhs.ident == **rhs) - } - - _ => false, - } -} - -pub fn type_is_unit(ty: &ReturnType) -> bool { - if let ReturnType::Type(_, ty) = ty { - if let Type::Tuple(ref tuple) = **ty { - tuple.elems.is_empty() - } else { - false - } - } else { - true - } -} |