@@ -6,14 +6,15 @@ use syn::{
66 parse:: { Parse , ParseBuffer } ,
77 parse_file,
88 punctuated:: Punctuated ,
9- Attribute , Generics , Ident , Item , ItemEnum , ItemMacro , ItemStruct , Token , Variant , Visibility ,
10- WhereClause ,
9+ Attribute , Generics , Ident , Item , ItemEnum , ItemMacro , ItemStruct , Meta , Token , Variant ,
10+ Visibility , WhereClause ,
1111} ;
1212
1313use crate :: schema:: FileId ;
1414
1515use super :: {
1616 ident_name,
17+ parse:: convert_expr_to_string,
1718 skeleton:: { EnumSkeleton , Skeleton , StructSkeleton } ,
1819 FxIndexMap ,
1920} ;
@@ -59,20 +60,12 @@ pub fn load_file(file_id: FileId, file_path: &str, skeletons: &mut FxIndexMap<St
5960}
6061
6162fn parse_struct ( item : ItemStruct , file_id : FileId ) -> Option < StructSkeleton > {
62- if !has_ast_attr ( & item. attrs ) {
63- return None ;
64- }
65-
66- let name = ident_name ( & item. ident ) ;
63+ let name = get_type_name ( & item. attrs , & item. ident ) ?;
6764 Some ( StructSkeleton { name, file_id, item } )
6865}
6966
7067fn parse_enum ( item : ItemEnum , file_id : FileId ) -> Option < EnumSkeleton > {
71- if !has_ast_attr ( & item. attrs ) {
72- return None ;
73- }
74-
75- let name = ident_name ( & item. ident ) ;
68+ let name = get_type_name ( & item. attrs , & item. ident ) ?;
7669 Some ( EnumSkeleton { name, file_id, item, inherits : vec ! [ ] } )
7770}
7871
@@ -96,15 +89,13 @@ fn parse_macro(item: &ItemMacro, file_id: FileId) -> Option<EnumSkeleton> {
9689 let ident = input. parse :: < Ident > ( ) ?;
9790 let generics = input. parse :: < Generics > ( ) ?;
9891
99- let name = ident_name ( & ident) ;
100-
10192 let where_clause = input. parse :: < Option < WhereClause > > ( ) ?;
10293 assert ! ( where_clause. is_none( ) , "Types with `where` clauses are not supported" ) ;
10394
104- assert ! (
105- has_ast_attr ( & attrs ) ,
106- "Enum in `inherit_variants!` macro must have `#[ast]` attr: {name}" ,
107- ) ;
95+ let name = get_type_name ( & attrs , & ident ) ;
96+ let Some ( name ) = name else {
97+ panic ! ( "Enum in `inherit_variants!` macro must have `#[ast]` attr: {ident}" ) ;
98+ } ;
10899
109100 let content;
110101 let brace_token = braced ! ( content in input) ;
@@ -133,7 +124,61 @@ fn parse_macro(item: &ItemMacro, file_id: FileId) -> Option<EnumSkeleton> {
133124 Some ( skeleton)
134125}
135126
136- /// Returns `true` if type has an `#[ast]` attribute on it.
137- fn has_ast_attr ( attrs : & [ Attribute ] ) -> bool {
138- attrs. iter ( ) . any ( |attr| attr. path ( ) . is_ident ( "ast" ) )
127+ /// Get name of type.
128+ ///
129+ /// Parse attributes and find `#[ast]` attr, or `#[ast(foreign = ForeignType)]`.
130+ ///
131+ /// If no `#[ast]` attr is present, returns `None`.
132+ ///
133+ /// Otherwise, returns foreign name if provided with `#[ast(foreign = ForeignType)]`,
134+ /// or otherwise name of the `ident`.
135+ ///
136+ /// # Panics
137+ /// Panics if cannot parse `#[ast]` attribute.
138+ fn get_type_name ( attrs : & [ Attribute ] , ident : & Ident ) -> Option < String > {
139+ let mut has_ast_attr = false ;
140+ let mut foreign_name = None ;
141+ for attr in attrs {
142+ if attr. path ( ) . is_ident ( "ast" ) {
143+ has_ast_attr = true ;
144+ if let Some ( this_foreign_name) = parse_ast_attr_foreign_name ( attr, ident) {
145+ assert ! (
146+ foreign_name. is_none( ) ,
147+ "Multiple `#[ast(foreign)]` attributes on type: `{ident}`"
148+ ) ;
149+ foreign_name = Some ( this_foreign_name) ;
150+ }
151+ }
152+ }
153+
154+ if has_ast_attr {
155+ Some ( foreign_name. unwrap_or_else ( || ident_name ( ident) ) )
156+ } else {
157+ None
158+ }
159+ }
160+
161+ fn parse_ast_attr_foreign_name ( attr : & Attribute , ident : & Ident ) -> Option < String > {
162+ let meta_list = match & attr. meta {
163+ Meta :: Path ( _) => return None ,
164+ Meta :: List ( meta_list) => meta_list,
165+ Meta :: NameValue ( _) => panic ! ( "Failed to parse `#[ast]` attribute" ) ,
166+ } ;
167+ let metas = meta_list
168+ . parse_args_with ( Punctuated :: < Meta , Token ! [ , ] > :: parse_terminated)
169+ . expect ( "Unable to parse `#[ast]` attribute" ) ;
170+
171+ let mut foreign_name = None ;
172+ for meta in & metas {
173+ if let Meta :: NameValue ( name_value) = meta {
174+ if name_value. path . is_ident ( "foreign" ) {
175+ assert ! (
176+ foreign_name. is_none( ) ,
177+ "Multiple `#[ast(foreign)]` attributes on type: `{ident}`"
178+ ) ;
179+ foreign_name = Some ( convert_expr_to_string ( & name_value. value ) ) ;
180+ }
181+ }
182+ }
183+ foreign_name
139184}
0 commit comments