Parse function pointer types
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 58237f3..3d35f78 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -3,11 +3,11 @@
     Ty1, Type, Var,
 };
 use proc_macro2::Ident;
-use quote::quote;
+use quote::{format_ident, quote};
 use syn::{
     Abi, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType, GenericArgument, Item,
-    ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Type as RustType, TypePath,
-    TypeReference,
+    ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Type as RustType,
+    TypeBareFn, TypePath, TypeReference,
 };
 
 pub fn parse_items(items: Vec<Item>) -> Result<Vec<Api>> {
@@ -176,32 +176,7 @@
     }
 
     let mut throws = false;
-    let ret = match &foreign_fn.sig.output {
-        ReturnType::Default => None,
-        ReturnType::Type(_, ret) => {
-            let mut ret = ret.as_ref();
-            if let RustType::Path(ty) = ret {
-                let path = &ty.path;
-                if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
-                    let segment = &path.segments[0];
-                    let ident = segment.ident.clone();
-                    if let PathArguments::AngleBracketed(generic) = &segment.arguments {
-                        if ident == "Result" && generic.args.len() == 1 {
-                            if let GenericArgument::Type(arg) = &generic.args[0] {
-                                ret = arg;
-                                throws = true;
-                            }
-                        }
-                    }
-                }
-            }
-            match parse_type(ret)? {
-                Type::Void(_) => None,
-                ty => Some(ty),
-            }
-        }
-    };
-
+    let ret = parse_return_type(&foreign_fn.sig.output, &mut throws)?;
     let doc = attrs::parse_doc(&foreign_fn.attrs)?;
     let fn_token = foreign_fn.sig.fn_token;
     let ident = foreign_fn.sig.ident.clone();
@@ -230,6 +205,7 @@
     match ty {
         RustType::Reference(ty) => parse_type_reference(ty),
         RustType::Path(ty) => parse_type_path(ty),
+        RustType::BareFn(ty) => parse_type_fn(ty),
         RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
         _ => Err(Error::new_spanned(ty, "unsupported type")),
     }
@@ -290,6 +266,71 @@
     Err(Error::new_spanned(ty, "unsupported type"))
 }
 
+fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
+    if ty.lifetimes.is_some() {
+        return Err(Error::new_spanned(
+            ty,
+            "function pointer with lifetime parameters is not supported yet",
+        ));
+    }
+    if ty.variadic.is_some() {
+        return Err(Error::new_spanned(
+            ty,
+            "variadic function pointer is not supported yet",
+        ));
+    }
+    let args = ty
+        .inputs
+        .iter()
+        .enumerate()
+        .map(|(i, arg)| {
+            let ty = parse_type(&arg.ty)?;
+            let ident = match &arg.name {
+                Some(ident) => ident.0.clone(),
+                None => format_ident!("_{}", i),
+            };
+            Ok(Var { ident, ty })
+        })
+        .collect::<Result<_>>()?;
+    let mut throws = false;
+    let ret = parse_return_type(&ty.output, &mut throws)?;
+    let tokens = quote!(#ty);
+    Ok(Type::Fn(Box::new(Signature {
+        fn_token: ty.fn_token,
+        receiver: None,
+        args,
+        ret,
+        throws,
+        tokens,
+    })))
+}
+
+fn parse_return_type(ty: &ReturnType, throws: &mut bool) -> Result<Option<Type>> {
+    let mut ret = match ty {
+        ReturnType::Default => return Ok(None),
+        ReturnType::Type(_, ret) => ret.as_ref(),
+    };
+    if let RustType::Path(ty) = ret {
+        let path = &ty.path;
+        if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
+            let segment = &path.segments[0];
+            let ident = segment.ident.clone();
+            if let PathArguments::AngleBracketed(generic) = &segment.arguments {
+                if ident == "Result" && generic.args.len() == 1 {
+                    if let GenericArgument::Type(arg) = &generic.args[0] {
+                        ret = arg;
+                        *throws = true;
+                    }
+                }
+            }
+        }
+    }
+    match parse_type(ret)? {
+        Type::Void(_) => Ok(None),
+        ty => Ok(Some(ty)),
+    }
+}
+
 fn check_reserved_name(ident: &Ident) -> Result<()> {
     if ident == "Box" || ident == "UniquePtr" || Atom::from(ident).is_some() {
         Err(Error::new(ident.span(), "reserved name"))