1use crate::bridge_module_attributes::CfgAttr;
2use crate::bridged_type::BridgedType;
3use crate::errors::{ParseError, ParseErrors};
4use crate::parse::parse_enum::SharedEnumDeclarationParser;
5use crate::parse::parse_extern_mod::ForeignModParser;
6use crate::parse::parse_struct::SharedStructDeclarationParser;
7use crate::SwiftBridgeModule;
8use proc_macro2::TokenTree;
9use quote::{quote, ToTokens};
10use syn::parse::{Parse, ParseStream};
11use syn::{Item, ItemMod, Token};
12
13mod parse_enum;
14mod parse_extern_mod;
15mod parse_struct;
16
17mod type_declarations;
18pub(crate) use self::type_declarations::*;
19
20impl Parse for SwiftBridgeModule {
21 fn parse(input: ParseStream) -> syn::Result<Self> {
22 let module_and_errors: SwiftBridgeModuleAndErrors = input.parse()?;
23
24 module_and_errors.errors.combine_all()?;
25
26 Ok(module_and_errors.module)
27 }
28}
29
30pub(crate) struct SwiftBridgeModuleAndErrors {
31 pub module: SwiftBridgeModule,
32 pub errors: ParseErrors,
33}
34
35#[derive(Debug, PartialEq, Copy, Clone)]
37pub(crate) enum HostLang {
38 Rust,
40 Swift,
42}
43
44impl HostLang {
45 pub fn is_rust(&self) -> bool {
46 matches!(self, HostLang::Rust)
47 }
48
49 pub fn is_swift(&self) -> bool {
50 matches!(self, HostLang::Swift)
51 }
52}
53
54impl Parse for SwiftBridgeModuleAndErrors {
55 fn parse(input: ParseStream) -> syn::Result<Self> {
56 let mut errors = ParseErrors::new();
57
58 if let Ok(item_mod) = input.parse::<ItemMod>() {
59 let module_name = item_mod.ident;
60 let vis = item_mod.vis;
61
62 let mut functions = vec![];
63 let mut type_declarations = TypeDeclarations::default();
64 let mut unresolved_types = vec![];
65 let mut cfg_attrs = vec![];
66
67 for attr in item_mod.attrs {
68 match attr.path.to_token_stream().to_string().as_str() {
69 "cfg" => {
70 let cfg: CfgAttr = syn::parse2(attr.tokens)?;
71 cfg_attrs.push(cfg);
72 }
73 _ => {}
74 };
75 }
76
77 for outer_mod_item in item_mod.content.unwrap().1 {
78 match outer_mod_item {
79 Item::ForeignMod(foreign_mod) => {
80 ForeignModParser {
81 errors: &mut errors,
82 type_declarations: &mut type_declarations,
83 functions: &mut functions,
84 unresolved_types: &mut unresolved_types,
85 }
86 .parse(foreign_mod)?;
87 }
88 Item::Struct(item_struct) => {
89 let shared_struct = SharedStructDeclarationParser {
90 item_struct,
91 errors: &mut errors,
92 }
93 .parse()?;
94 type_declarations.insert(
95 shared_struct.name.to_string(),
96 TypeDeclaration::Shared(SharedTypeDeclaration::Struct(shared_struct)),
97 );
98 }
99 Item::Enum(item_enum) => {
100 let shared_enum = SharedEnumDeclarationParser {
101 item_enum,
102 errors: &mut errors,
103 }
104 .parse()?;
105 type_declarations.insert(
106 shared_enum.name.to_string(),
107 TypeDeclaration::Shared(SharedTypeDeclaration::Enum(shared_enum)),
108 );
109 }
110 invalid_item => {
111 let error = ParseError::InvalidModuleItem { item: invalid_item };
112 errors.push(error);
113 }
114 };
115 }
116
117 for unresolved_type in unresolved_types.into_iter() {
118 if BridgedType::new_with_type(&unresolved_type, &type_declarations).is_some() {
119 continue;
120 }
121
122 errors.push(ParseError::UndeclaredType {
123 ty: unresolved_type.clone(),
124 });
125 }
126
127 let module = SwiftBridgeModule {
128 name: module_name,
129 vis,
130 types: type_declarations,
131 functions,
132 swift_bridge_path: syn::parse2(quote! { swift_bridge }).unwrap(),
133 cfg_attrs,
134 };
135 Ok(SwiftBridgeModuleAndErrors { module, errors })
136 } else {
137 return Err(syn::Error::new_spanned(
138 input.to_string(),
139 "Only modules are supported.",
140 ));
141 }
142 }
143}
144
145fn move_input_cursor_to_next_comma(input: ParseStream) {
148 if !input.peek(Token![,]) {
149 let _ = input.step(|cursor| {
150 let mut current_cursor = *cursor;
151
152 while let Some((tt, next)) = current_cursor.token_tree() {
153 match &tt {
154 TokenTree::Punct(punct) if punct.as_char() == ',' => {
155 return Ok(((), current_cursor));
156 }
157 _ => current_cursor = next,
158 }
159 }
160
161 Ok(((), current_cursor))
162 });
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::test_utils::{parse_errors, parse_ok};
170
171 #[test]
173 fn parse_module_cfg_feature() {
174 let tokens = quote! {
175 #[swift_bridge::bridge]
176 #[cfg(feature = "some-feature")]
177 mod foo {}
178 };
179
180 let module = parse_ok(tokens);
181
182 assert_eq!(module.cfg_attrs.len(), 1);
183
184 match &module.cfg_attrs[0] {
185 CfgAttr::Feature(feature) => {
186 assert_eq!(feature.value(), "some-feature")
187 }
188 };
189 }
190
191 #[test]
194 fn invalid_module_item() {
195 let tokens = quote! {
196 #[swift_bridge::bridge]
197 mod foo {
198 use std;
199 }
200 };
201
202 let errors = parse_errors(tokens);
203
204 assert_eq!(errors.len(), 1);
205 match &errors[0] {
206 ParseError::InvalidModuleItem { item } => {
207 assert!(matches!(item, Item::Use(_)))
208 }
209 _ => panic!(),
210 }
211 }
212}