blob: 0a86b6cdb42dd7be5075bb6f104145daf9a2fffb [file] [log] [blame]
David Tolnay17e137f2020-05-08 15:55:28 -07001use crate::syntax::discriminant::DiscriminantSet;
David Tolnayc598a272020-08-29 15:10:18 -07002use crate::syntax::file::{Item, ItemForeignMod};
David Tolnay52759782020-05-03 23:59:40 -07003use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07004use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04005use crate::syntax::{
Adrian Taylorc8713432020-10-21 18:20:55 -07006 attrs, error, Api, CppName, Doc, Enum, ExternFn, ExternType, Impl, Lang, Namespace, Pair,
7 Receiver, Ref, ResolvableName, Signature, Slice, Struct, Ty1, Type, TypeAlias, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04008};
David Tolnay7e69f892020-10-03 22:20:22 -07009use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
David Tolnaye2e303f2020-05-10 20:52:00 -070010use quote::{format_ident, quote, quote_spanned};
David Tolnaye2f9ec42020-05-07 16:19:33 -070011use syn::parse::{ParseStream, Parser};
David Tolnaye3a48152020-04-08 19:38:05 -070012use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040013use syn::{
David Tolnay17e137f2020-05-08 15:55:28 -070014 Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
David Tolnay7e69f892020-10-03 22:20:22 -070015 GenericArgument, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat, PathArguments, Result,
16 ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
David Tolnay7db73692019-10-20 14:51:12 -040017};
18
David Tolnaye3a48152020-04-08 19:38:05 -070019pub mod kw {
20 syn::custom_keyword!(Result);
21}
22
Adrian Taylorc8713432020-10-21 18:20:55 -070023pub fn parse_items(cx: &mut Errors, items: Vec<Item>, trusted: bool, ns: &Namespace) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040024 let mut apis = Vec::new();
25 for item in items {
26 match item {
Adrian Taylorc8713432020-10-21 18:20:55 -070027 Item::Struct(item) => match parse_struct(cx, item, ns.clone()) {
David Tolnay52759782020-05-03 23:59:40 -070028 Ok(strct) => apis.push(strct),
29 Err(err) => cx.push(err),
30 },
Adrian Taylorc8713432020-10-21 18:20:55 -070031 Item::Enum(item) => match parse_enum(cx, item, ns.clone()) {
David Tolnay52759782020-05-03 23:59:40 -070032 Ok(enm) => apis.push(enm),
33 Err(err) => cx.push(err),
34 },
Adrian Taylorc8713432020-10-21 18:20:55 -070035 Item::ForeignMod(foreign_mod) => {
36 parse_foreign_mod(cx, foreign_mod, &mut apis, trusted, ns)
37 }
38 Item::Impl(item) => match parse_impl(item, ns) {
David Tolnay7e69f892020-10-03 22:20:22 -070039 Ok(imp) => apis.push(imp),
40 Err(err) => cx.push(err),
41 },
David Tolnay52759782020-05-03 23:59:40 -070042 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
David Tolnay00a83852020-08-29 15:06:16 -070043 Item::Other(item) => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040044 }
45 }
David Tolnay52759782020-05-03 23:59:40 -070046 apis
David Tolnay7db73692019-10-20 14:51:12 -040047}
48
Adrian Taylorc8713432020-10-21 18:20:55 -070049fn parse_struct(cx: &mut Errors, item: ItemStruct, mut ns: Namespace) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040050 let generics = &item.generics;
51 if !generics.params.is_empty() || generics.where_clause.is_some() {
52 let struct_token = item.struct_token;
53 let ident = &item.ident;
54 let where_clause = &generics.where_clause;
55 let span = quote!(#struct_token #ident #generics #where_clause);
56 return Err(Error::new_spanned(
57 span,
58 "struct with generic parameters is not supported yet",
59 ));
60 }
61
62 let mut doc = Doc::new();
63 let mut derives = Vec::new();
David Tolnayb129ea72020-05-10 14:29:30 -070064 attrs::parse(
David Tolnay3e628882020-05-10 15:30:14 -070065 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070066 &item.attrs,
67 attrs::Parser {
68 doc: Some(&mut doc),
69 derives: Some(&mut derives),
Adrian Taylorc8713432020-10-21 18:20:55 -070070 namespace: Some(&mut ns),
David Tolnayddf69e22020-05-10 22:08:20 -070071 ..Default::default()
David Tolnayb129ea72020-05-10 14:29:30 -070072 },
David Tolnay3e628882020-05-10 15:30:14 -070073 );
David Tolnay09462ac2020-03-20 14:58:41 -070074
75 let fields = match item.fields {
76 Fields::Named(fields) => fields,
77 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
78 Fields::Unnamed(_) => {
David Tolnay2c4b35f2020-10-04 21:22:30 -070079 return Err(Error::new_spanned(item, "tuple structs are not supported"));
David Tolnay09462ac2020-03-20 14:58:41 -070080 }
81 };
82
83 Ok(Api::Struct(Struct {
84 doc,
85 derives,
86 struct_token: item.struct_token,
Adrian Taylorc8713432020-10-21 18:20:55 -070087 ident: Pair::new(ns.clone(), item.ident),
David Tolnay09462ac2020-03-20 14:58:41 -070088 brace_token: fields.brace_token,
89 fields: fields
90 .named
91 .into_iter()
92 .map(|field| {
93 Ok(Var {
94 ident: field.ident.unwrap(),
Adrian Taylorc8713432020-10-21 18:20:55 -070095 ty: parse_type(&field.ty, &ns)?,
David Tolnay7db73692019-10-20 14:51:12 -040096 })
David Tolnay09462ac2020-03-20 14:58:41 -070097 })
98 .collect::<Result<_>>()?,
99 }))
David Tolnay7db73692019-10-20 14:51:12 -0400100}
101
Adrian Taylorc8713432020-10-21 18:20:55 -0700102fn parse_enum(cx: &mut Errors, item: ItemEnum, mut ns: Namespace) -> Result<Api> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700103 let generics = &item.generics;
104 if !generics.params.is_empty() || generics.where_clause.is_some() {
105 let enum_token = item.enum_token;
106 let ident = &item.ident;
107 let where_clause = &generics.where_clause;
108 let span = quote!(#enum_token #ident #generics #where_clause);
109 return Err(Error::new_spanned(
110 span,
111 "enums with generic parameters are not allowed",
112 ));
113 }
114
David Tolnayddf69e22020-05-10 22:08:20 -0700115 let mut doc = Doc::new();
116 let mut repr = None;
117 attrs::parse(
118 cx,
119 &item.attrs,
120 attrs::Parser {
121 doc: Some(&mut doc),
122 repr: Some(&mut repr),
Adrian Taylorc8713432020-10-21 18:20:55 -0700123 namespace: Some(&mut ns),
David Tolnayddf69e22020-05-10 22:08:20 -0700124 ..Default::default()
125 },
126 );
Joel Galensonc03402a2020-04-23 17:31:09 -0700127
Joel Galenson88547732020-05-05 08:23:42 -0700128 let mut variants = Vec::new();
David Tolnayddf69e22020-05-10 22:08:20 -0700129 let mut discriminants = DiscriminantSet::new(repr);
Joel Galenson88547732020-05-05 08:23:42 -0700130 for variant in item.variants {
131 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700132 Fields::Unit => {}
133 _ => {
David Tolnay0435a812020-05-10 21:58:15 -0700134 cx.error(variant, "enums with data are not supported yet");
135 break;
Joel Galensonc03402a2020-04-23 17:31:09 -0700136 }
137 }
David Tolnay17e137f2020-05-08 15:55:28 -0700138 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
139 let try_discriminant = match &expr {
140 Some(lit) => discriminants.insert(lit),
141 None => discriminants.insert_next(),
142 };
143 let discriminant = match try_discriminant {
144 Ok(discriminant) => discriminant,
David Tolnay0435a812020-05-10 21:58:15 -0700145 Err(err) => {
146 cx.error(variant, err);
147 break;
148 }
David Tolnay17e137f2020-05-08 15:55:28 -0700149 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700150 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700151 variants.push(Variant {
152 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700153 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700154 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700155 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700156 }
157
David Tolnaye2e303f2020-05-10 20:52:00 -0700158 let enum_token = item.enum_token;
159 let brace_token = item.brace_token;
160
David Tolnay0435a812020-05-10 21:58:15 -0700161 let mut repr = U8;
162 match discriminants.inferred_repr() {
163 Ok(inferred) => repr = inferred,
David Tolnaye2e303f2020-05-10 20:52:00 -0700164 Err(err) => {
165 let span = quote_spanned!(brace_token.span=> #enum_token {});
David Tolnay0435a812020-05-10 21:58:15 -0700166 cx.error(span, err);
167 variants.clear();
David Tolnaye2e303f2020-05-10 20:52:00 -0700168 }
David Tolnay0435a812020-05-10 21:58:15 -0700169 }
David Tolnaye2e303f2020-05-10 20:52:00 -0700170
Joel Galensonc03402a2020-04-23 17:31:09 -0700171 Ok(Api::Enum(Enum {
172 doc,
David Tolnaye2e303f2020-05-10 20:52:00 -0700173 enum_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700174 ident: Pair::new(ns, item.ident),
David Tolnaye2e303f2020-05-10 20:52:00 -0700175 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700176 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700177 repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700178 }))
179}
180
David Tolnay805dca32020-08-29 19:09:55 -0700181fn parse_foreign_mod(
182 cx: &mut Errors,
183 foreign_mod: ItemForeignMod,
184 out: &mut Vec<Api>,
185 trusted: bool,
Adrian Taylorc8713432020-10-21 18:20:55 -0700186 ns: &Namespace,
David Tolnay805dca32020-08-29 19:09:55 -0700187) {
David Tolnay3a451732020-08-29 18:54:55 -0700188 let lang = match parse_lang(&foreign_mod.abi) {
David Tolnay52759782020-05-03 23:59:40 -0700189 Ok(lang) => lang,
190 Err(err) => return cx.push(err),
191 };
David Tolnay7db73692019-10-20 14:51:12 -0400192
David Tolnay3a451732020-08-29 18:54:55 -0700193 match lang {
194 Lang::Rust => {
David Tolnay805dca32020-08-29 19:09:55 -0700195 if foreign_mod.unsafety.is_some() {
David Tolnay3a451732020-08-29 18:54:55 -0700196 let unsafety = foreign_mod.unsafety;
197 let abi = foreign_mod.abi;
198 let span = quote!(#unsafety #abi);
199 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
200 }
201 }
202 Lang::Cxx => {}
203 }
204
David Tolnay805dca32020-08-29 19:09:55 -0700205 let trusted = trusted || foreign_mod.unsafety.is_some();
206
Joel Galensone1e969d2020-04-21 12:50:20 -0700207 let mut items = Vec::new();
208 for foreign in &foreign_mod.items {
209 match foreign {
Adrian Taylorc8713432020-10-21 18:20:55 -0700210 ForeignItem::Type(foreign) => {
211 match parse_extern_type(cx, foreign, lang, trusted, ns.clone()) {
212 Ok(ety) => items.push(ety),
213 Err(err) => cx.push(err),
214 }
215 }
216 ForeignItem::Fn(foreign) => match parse_extern_fn(cx, foreign, lang, ns.clone()) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700217 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700218 Err(err) => cx.push(err),
219 },
David Tolnay7db73692019-10-20 14:51:12 -0400220 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay91e87fa2020-05-11 19:10:23 -0700221 match foreign.mac.parse_body_with(parse_include) {
David Tolnay52759782020-05-03 23:59:40 -0700222 Ok(include) => items.push(Api::Include(include)),
223 Err(err) => cx.push(err),
224 }
David Tolnay7db73692019-10-20 14:51:12 -0400225 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700226 ForeignItem::Verbatim(tokens) => {
227 match parse_extern_verbatim(cx, tokens, lang, ns.clone()) {
228 Ok(api) => items.push(api),
229 Err(err) => cx.push(err),
230 }
231 }
David Tolnay52759782020-05-03 23:59:40 -0700232 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400233 }
234 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700235
236 let mut types = items.iter().filter_map(|item| match item {
David Tolnay4cefa722020-10-03 21:24:07 -0700237 Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.ident),
David Tolnaye5a015a2020-05-07 21:54:26 -0700238 Api::TypeAlias(alias) => Some(&alias.ident),
David Tolnaya1f29c42020-04-22 18:01:38 -0700239 _ => None,
240 });
241 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700242 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700243 for item in &mut items {
244 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
245 if let Some(receiver) = &mut efn.receiver {
Adrian Taylorc8713432020-10-21 18:20:55 -0700246 if receiver.ty.is_self() {
247 receiver.ty = ResolvableName::from_pair(single_type.clone());
David Tolnaya1f29c42020-04-22 18:01:38 -0700248 }
249 }
250 }
251 }
252 }
253
David Tolnay52759782020-05-03 23:59:40 -0700254 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400255}
256
David Tolnay3a451732020-08-29 18:54:55 -0700257fn parse_lang(abi: &Abi) -> Result<Lang> {
David Tolnay7db73692019-10-20 14:51:12 -0400258 let name = match &abi.name {
259 Some(name) => name,
260 None => {
261 return Err(Error::new_spanned(
262 abi,
263 "ABI name is required, extern \"C\" or extern \"Rust\"",
264 ));
265 }
266 };
267 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700268 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400269 "Rust" => Ok(Lang::Rust),
270 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
271 }
272}
273
David Tolnay00f236a2020-08-29 19:07:18 -0700274fn parse_extern_type(
275 cx: &mut Errors,
276 foreign_type: &ForeignItemType,
277 lang: Lang,
278 trusted: bool,
Adrian Taylorc8713432020-10-21 18:20:55 -0700279 mut ns: Namespace,
David Tolnay00f236a2020-08-29 19:07:18 -0700280) -> Result<Api> {
Adrian Taylorc8713432020-10-21 18:20:55 -0700281 let mut doc = Doc::new();
282 attrs::parse(
283 cx,
284 &foreign_type.attrs,
285 attrs::Parser {
286 doc: Some(&mut doc),
287 namespace: Some(&mut ns),
288 ..Default::default()
289 },
290 );
David Tolnay7db73692019-10-20 14:51:12 -0400291 let type_token = foreign_type.type_token;
292 let ident = foreign_type.ident.clone();
David Tolnayc8361022020-08-25 21:57:53 -0700293 let semi_token = foreign_type.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700294 let api_type = match lang {
295 Lang::Cxx => Api::CxxType,
296 Lang::Rust => Api::RustType,
297 };
298 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400299 doc,
300 type_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700301 ident: Pair::new(ns, ident),
David Tolnayc8361022020-08-25 21:57:53 -0700302 semi_token,
David Tolnay00f236a2020-08-29 19:07:18 -0700303 trusted,
David Tolnay295ef6b2020-05-07 16:10:22 -0700304 }))
David Tolnay7db73692019-10-20 14:51:12 -0400305}
306
Adrian Taylorc8713432020-10-21 18:20:55 -0700307fn parse_extern_fn(
308 cx: &mut Errors,
309 foreign_fn: &ForeignItemFn,
310 lang: Lang,
311 mut ns: Namespace,
312) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400313 let generics = &foreign_fn.sig.generics;
314 if !generics.params.is_empty() || generics.where_clause.is_some() {
315 return Err(Error::new_spanned(
316 foreign_fn,
317 "extern function with generic parameters is not supported yet",
318 ));
319 }
320 if let Some(variadic) = &foreign_fn.sig.variadic {
321 return Err(Error::new_spanned(
322 variadic,
323 "variadic function is not supported yet",
324 ));
325 }
326
David Tolnay938ca852020-10-09 19:25:08 -0700327 let mut doc = Doc::new();
328 let mut cxx_name = None;
329 let mut rust_name = None;
330 attrs::parse(
331 cx,
332 &foreign_fn.attrs,
333 attrs::Parser {
334 doc: Some(&mut doc),
335 cxx_name: Some(&mut cxx_name),
336 rust_name: Some(&mut rust_name),
Adrian Taylorc8713432020-10-21 18:20:55 -0700337 namespace: Some(&mut ns),
David Tolnay938ca852020-10-09 19:25:08 -0700338 ..Default::default()
339 },
340 );
341
David Tolnay7db73692019-10-20 14:51:12 -0400342 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700343 let mut args = Punctuated::new();
344 for arg in foreign_fn.sig.inputs.pairs() {
345 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400346 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700347 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700348 if let Some((ampersand, lifetime)) = &arg.reference {
349 receiver = Some(Receiver {
350 ampersand: *ampersand,
351 lifetime: lifetime.clone(),
352 mutability: arg.mutability,
353 var: arg.self_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700354 ty: ResolvableName::make_self(arg.self_token.span),
David Tolnaya1f29c42020-04-22 18:01:38 -0700355 shorthand: true,
356 });
357 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700358 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700359 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400360 }
361 FnArg::Typed(arg) => {
362 let ident = match arg.pat.as_ref() {
363 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700364 Pat::Wild(pat) => {
365 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
366 }
David Tolnay7db73692019-10-20 14:51:12 -0400367 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
368 };
Adrian Taylorc8713432020-10-21 18:20:55 -0700369 let ty = parse_type(&arg.ty, &ns)?;
David Tolnay7db73692019-10-20 14:51:12 -0400370 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700371 args.push_value(Var { ident, ty });
372 if let Some(comma) = comma {
373 args.push_punct(*comma);
374 }
David Tolnay7db73692019-10-20 14:51:12 -0400375 continue;
376 }
377 if let Type::Ref(reference) = ty {
378 if let Type::Ident(ident) = reference.inner {
379 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700380 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700381 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400382 mutability: reference.mutability,
Adrian Taylorc8713432020-10-21 18:20:55 -0700383 var: Token![self](ident.rust.span()),
David Tolnay05e11cc2020-04-20 02:13:56 -0700384 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700385 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400386 });
387 continue;
388 }
389 }
390 return Err(Error::new_spanned(arg, "unsupported method receiver"));
391 }
392 }
393 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700394
David Tolnaye3a48152020-04-08 19:38:05 -0700395 let mut throws_tokens = None;
Adrian Taylorc8713432020-10-21 18:20:55 -0700396 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens, &ns)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700397 let throws = throws_tokens.is_some();
David Tolnaybdb576c2020-09-06 23:45:55 -0700398 let unsafety = foreign_fn.sig.unsafety;
David Tolnay7db73692019-10-20 14:51:12 -0400399 let fn_token = foreign_fn.sig.fn_token;
David Tolnay938ca852020-10-09 19:25:08 -0700400 let ident = Pair {
Adrian Taylorc8713432020-10-21 18:20:55 -0700401 cxx: CppName::new(ns, cxx_name.unwrap_or(foreign_fn.sig.ident.clone())),
David Tolnay938ca852020-10-09 19:25:08 -0700402 rust: rust_name.unwrap_or(foreign_fn.sig.ident.clone()),
403 };
David Tolnaye3a48152020-04-08 19:38:05 -0700404 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400405 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700406 let api_function = match lang {
407 Lang::Cxx => Api::CxxFunction,
408 Lang::Rust => Api::RustFunction,
409 };
David Tolnayd95b1192020-03-18 20:07:46 -0700410
David Tolnay295ef6b2020-05-07 16:10:22 -0700411 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700412 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400413 doc,
David Tolnay938ca852020-10-09 19:25:08 -0700414 ident,
David Tolnay16448732020-03-18 12:39:36 -0700415 sig: Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700416 unsafety,
David Tolnay16448732020-03-18 12:39:36 -0700417 fn_token,
418 receiver,
419 args,
420 ret,
421 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700422 paren_token,
423 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700424 },
David Tolnay7db73692019-10-20 14:51:12 -0400425 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700426 }))
David Tolnay7db73692019-10-20 14:51:12 -0400427}
428
Adrian Taylorc8713432020-10-21 18:20:55 -0700429fn parse_extern_verbatim(
430 cx: &mut Errors,
431 tokens: &TokenStream,
432 lang: Lang,
433 mut ns: Namespace,
434) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700435 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700436 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700437 let attrs = input.call(Attribute::parse_outer)?;
438 let type_token: Token![type] = match input.parse()? {
439 Some(type_token) => type_token,
440 None => {
441 let span = input.cursor().token_stream();
442 return Err(Error::new_spanned(span, "unsupported foreign item"));
443 }
444 };
445 let ident: Ident = input.parse()?;
446 let eq_token: Token![=] = input.parse()?;
447 let ty: RustType = input.parse()?;
448 let semi_token: Token![;] = input.parse()?;
Adrian Taylorc8713432020-10-21 18:20:55 -0700449 let mut doc = Doc::new();
450 attrs::parse(
451 cx,
452 &attrs,
453 attrs::Parser {
454 doc: Some(&mut doc),
455 namespace: Some(&mut ns),
456 ..Default::default()
457 },
458 );
David Tolnaye2f9ec42020-05-07 16:19:33 -0700459
460 Ok(TypeAlias {
Bryan Henry890083d2020-09-13 10:34:31 -0700461 doc,
David Tolnaye2f9ec42020-05-07 16:19:33 -0700462 type_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700463 ident: Pair::new(ns, ident),
David Tolnaye2f9ec42020-05-07 16:19:33 -0700464 eq_token,
465 ty,
466 semi_token,
467 })
David Tolnay3e628882020-05-10 15:30:14 -0700468 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700469
470 let type_alias = parse.parse2(tokens.clone())?;
471 match lang {
472 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
473 Lang::Rust => {
474 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
475 let span = quote!(#type_token #semi_token);
476 let msg = "type alias in extern \"Rust\" block is not supported";
477 Err(Error::new_spanned(span, msg))
478 }
479 }
480}
481
Adrian Taylorc8713432020-10-21 18:20:55 -0700482fn parse_impl(imp: ItemImpl, ns: &Namespace) -> Result<Api> {
David Tolnay7e69f892020-10-03 22:20:22 -0700483 if !imp.items.is_empty() {
484 let mut span = Group::new(Delimiter::Brace, TokenStream::new());
485 span.set_span(imp.brace_token.span);
486 return Err(Error::new_spanned(span, "expected an empty impl block"));
487 }
488
489 let self_ty = &imp.self_ty;
490 if let Some((bang, path, for_token)) = &imp.trait_ {
491 let span = quote!(#bang #path #for_token #self_ty);
492 return Err(Error::new_spanned(
493 span,
494 "unexpected impl, expected something like `impl UniquePtr<T> {}`",
495 ));
496 }
497
498 let generics = &imp.generics;
499 if !generics.params.is_empty() || generics.where_clause.is_some() {
500 return Err(Error::new_spanned(
501 imp,
502 "generic parameters on an impl is not supported",
503 ));
504 }
505
506 Ok(Api::Impl(Impl {
507 impl_token: imp.impl_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700508 ty: parse_type(&self_ty, ns)?,
David Tolnay7e69f892020-10-03 22:20:22 -0700509 brace_token: imp.brace_token,
510 }))
511}
512
David Tolnay91e87fa2020-05-11 19:10:23 -0700513fn parse_include(input: ParseStream) -> Result<String> {
514 if input.peek(LitStr) {
515 return Ok(input.parse::<LitStr>()?.value());
516 }
517
518 if input.peek(Token![<]) {
519 let mut path = String::new();
520 input.parse::<Token![<]>()?;
521 path.push('<');
522 while !input.is_empty() && !input.peek(Token![>]) {
523 let token: TokenTree = input.parse()?;
524 match token {
525 TokenTree::Ident(token) => path += &token.to_string(),
526 TokenTree::Literal(token)
527 if token
528 .to_string()
529 .starts_with(|ch: char| ch.is_ascii_digit()) =>
530 {
531 path += &token.to_string();
532 }
533 TokenTree::Punct(token) => path.push(token.as_char()),
534 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
535 }
536 }
537 input.parse::<Token![>]>()?;
538 path.push('>');
539 return Ok(path);
540 }
541
542 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
543}
544
Adrian Taylorc8713432020-10-21 18:20:55 -0700545fn parse_type(ty: &RustType, ns: &Namespace) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700546 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700547 RustType::Reference(ty) => parse_type_reference(ty, ns),
548 RustType::Path(ty) => parse_type_path(ty, ns),
549 RustType::Slice(ty) => parse_type_slice(ty, ns),
550 RustType::BareFn(ty) => parse_type_fn(ty, ns),
David Tolnayb40b9db2020-03-18 13:50:31 -0700551 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
552 _ => Err(Error::new_spanned(ty, "unsupported type")),
553 }
554}
555
Adrian Taylorc8713432020-10-21 18:20:55 -0700556fn parse_type_reference(ty: &TypeReference, ns: &Namespace) -> Result<Type> {
557 let inner = parse_type(&ty.elem, ns)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700558 let which = match &inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700559 Type::Ident(ident) if ident.rust == "str" => {
David Tolnayb40b9db2020-03-18 13:50:31 -0700560 if ty.mutability.is_some() {
561 return Err(Error::new_spanned(ty, "unsupported type"));
562 } else {
563 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400564 }
565 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700566 Type::Slice(slice) => match &slice.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700567 Type::Ident(ident) if ident.rust == U8 && ty.mutability.is_none() => Type::SliceRefU8,
David Tolnayeebe9b72020-04-14 16:32:18 -0700568 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700569 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700570 _ => Type::Ref,
571 };
572 Ok(which(Box::new(Ref {
573 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700574 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700575 mutability: ty.mutability,
576 inner,
577 })))
578}
579
Adrian Taylorc8713432020-10-21 18:20:55 -0700580fn parse_type_path(ty: &TypePath, ns: &Namespace) -> Result<Type> {
David Tolnayb40b9db2020-03-18 13:50:31 -0700581 let path = &ty.path;
582 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
583 let segment = &path.segments[0];
584 let ident = segment.ident.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700585 let maybe_resolved_ident = ResolvableName::new(ident.clone());
David Tolnayb40b9db2020-03-18 13:50:31 -0700586 match &segment.arguments {
Adrian Taylorc8713432020-10-21 18:20:55 -0700587 PathArguments::None => return Ok(Type::Ident(maybe_resolved_ident)),
David Tolnayb40b9db2020-03-18 13:50:31 -0700588 PathArguments::AngleBracketed(generic) => {
589 if ident == "UniquePtr" && generic.args.len() == 1 {
590 if let GenericArgument::Type(arg) = &generic.args[0] {
Adrian Taylorc8713432020-10-21 18:20:55 -0700591 let inner = parse_type(arg, ns)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700592 return Ok(Type::UniquePtr(Box::new(Ty1 {
Adrian Taylorc8713432020-10-21 18:20:55 -0700593 name: maybe_resolved_ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700594 langle: generic.lt_token,
595 inner,
596 rangle: generic.gt_token,
597 })));
598 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700599 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700600 if let GenericArgument::Type(arg) = &generic.args[0] {
Adrian Taylorc8713432020-10-21 18:20:55 -0700601 let inner = parse_type(arg, ns)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700602 return Ok(Type::CxxVector(Box::new(Ty1 {
Adrian Taylorc8713432020-10-21 18:20:55 -0700603 name: maybe_resolved_ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700604 langle: generic.lt_token,
605 inner,
606 rangle: generic.gt_token,
607 })));
608 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700609 } else if ident == "Box" && generic.args.len() == 1 {
610 if let GenericArgument::Type(arg) = &generic.args[0] {
Adrian Taylorc8713432020-10-21 18:20:55 -0700611 let inner = parse_type(arg, ns)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700612 return Ok(Type::RustBox(Box::new(Ty1 {
Adrian Taylorc8713432020-10-21 18:20:55 -0700613 name: maybe_resolved_ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700614 langle: generic.lt_token,
615 inner,
616 rangle: generic.gt_token,
617 })));
618 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700619 } else if ident == "Vec" && generic.args.len() == 1 {
620 if let GenericArgument::Type(arg) = &generic.args[0] {
Adrian Taylorc8713432020-10-21 18:20:55 -0700621 let inner = parse_type(arg, ns)?;
Myron Ahneba35cf2020-02-05 19:41:51 +0700622 return Ok(Type::RustVec(Box::new(Ty1 {
Adrian Taylorc8713432020-10-21 18:20:55 -0700623 name: maybe_resolved_ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700624 langle: generic.lt_token,
625 inner,
626 rangle: generic.gt_token,
627 })));
628 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700629 }
630 }
631 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700632 }
David Tolnay7db73692019-10-20 14:51:12 -0400633 }
634 Err(Error::new_spanned(ty, "unsupported type"))
635}
636
Adrian Taylorc8713432020-10-21 18:20:55 -0700637fn parse_type_slice(ty: &TypeSlice, ns: &Namespace) -> Result<Type> {
638 let inner = parse_type(&ty.elem, ns)?;
David Tolnayeebe9b72020-04-14 16:32:18 -0700639 Ok(Type::Slice(Box::new(Slice {
640 bracket: ty.bracket_token,
641 inner,
642 })))
643}
644
Adrian Taylorc8713432020-10-21 18:20:55 -0700645fn parse_type_fn(ty: &TypeBareFn, ns: &Namespace) -> Result<Type> {
David Tolnayc071b892020-03-18 16:59:53 -0700646 if ty.lifetimes.is_some() {
647 return Err(Error::new_spanned(
648 ty,
649 "function pointer with lifetime parameters is not supported yet",
650 ));
651 }
652 if ty.variadic.is_some() {
653 return Err(Error::new_spanned(
654 ty,
655 "variadic function pointer is not supported yet",
656 ));
657 }
658 let args = ty
659 .inputs
660 .iter()
661 .enumerate()
662 .map(|(i, arg)| {
Adrian Taylorc8713432020-10-21 18:20:55 -0700663 let ty = parse_type(&arg.ty, ns)?;
David Tolnayc071b892020-03-18 16:59:53 -0700664 let ident = match &arg.name {
665 Some(ident) => ident.0.clone(),
666 None => format_ident!("_{}", i),
667 };
668 Ok(Var { ident, ty })
669 })
670 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700671 let mut throws_tokens = None;
Adrian Taylorc8713432020-10-21 18:20:55 -0700672 let ret = parse_return_type(&ty.output, &mut throws_tokens, ns)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700673 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700674 Ok(Type::Fn(Box::new(Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700675 unsafety: ty.unsafety,
David Tolnayc071b892020-03-18 16:59:53 -0700676 fn_token: ty.fn_token,
677 receiver: None,
678 args,
679 ret,
680 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700681 paren_token: ty.paren_token,
682 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700683 })))
684}
685
David Tolnaye3a48152020-04-08 19:38:05 -0700686fn parse_return_type(
687 ty: &ReturnType,
688 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
Adrian Taylorc8713432020-10-21 18:20:55 -0700689 ns: &Namespace,
David Tolnaye3a48152020-04-08 19:38:05 -0700690) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700691 let mut ret = match ty {
692 ReturnType::Default => return Ok(None),
693 ReturnType::Type(_, ret) => ret.as_ref(),
694 };
695 if let RustType::Path(ty) = ret {
696 let path = &ty.path;
697 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
698 let segment = &path.segments[0];
699 let ident = segment.ident.clone();
700 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
701 if ident == "Result" && generic.args.len() == 1 {
702 if let GenericArgument::Type(arg) = &generic.args[0] {
703 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700704 *throws_tokens =
705 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700706 }
707 }
708 }
709 }
710 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700711 match parse_type(ret, ns)? {
David Tolnayc071b892020-03-18 16:59:53 -0700712 Type::Void(_) => Ok(None),
713 ty => Ok(Some(ty)),
714 }
715}