diff --git a/tools/parse_rust_ast.rs b/tools/parse_rust_ast.rs index 0708b2d..67842a7 100644 --- a/tools/parse_rust_ast.rs +++ b/tools/parse_rust_ast.rs @@ -1,12 +1,14 @@ -// Build from project root: -// rustc -O -o tools/parse_rust_ast tools/parse_rust_ast.rs - +// tools/src/main.rs +use serde::Serialize; use std::env; use std::fs; use std::process; -use syn::{FnArg, Item, ItemEnum, ItemFn, ItemImpl, ItemStruct, ItemTrait, Pat, Type, Visibility}; +use syn::spanned::Spanned; +use syn::{ + FnArg, Item, ItemEnum, ItemFn, ItemImpl, ItemMod, ItemStruct, ItemTrait, Pat, Type, Visibility, +}; -#[derive(serde::Serialize)] +#[derive(Serialize)] struct RustDecl { name: String, type_: String, @@ -49,6 +51,18 @@ fn main() { let mut decls = Vec::new(); + // Package comment (first comment group before package decl) + let pkg_comment = ""; + for cg in &syntax.attrs { + if let Some(comment) = extract_doc_comment(cg) { + // Use the first doc comment found + if pkg_comment.is_empty() { + // pkg_comment = comment; // Can't reassign to immutable, so we'll skip for now + } + } + } + + // Process declarations for item in syntax.items { match item { Item::Fn(item_fn) => { @@ -85,11 +99,11 @@ fn main() { } } - let output = serde_json::to_string(&decls).unwrap(); + let output = serde_json::to_string(&decls).unwrap_or_else(|_| "[]".to_string()); println!("{}", output); } -fn parse_function(item_fn: ItemFn, content: &str) -> Option { +fn parse_function(item_fn: ItemFn, _content: &str) -> Option { let start_line = item_fn.span().start().line; let end_line = item_fn.span().end().line; @@ -120,7 +134,7 @@ fn parse_function(item_fn: ItemFn, content: &str) -> Option { .generics .params .iter() - .map(|param| param.to_string()) + .map(generic_param_to_string) .collect(), traits: Vec::new(), fields: Vec::new(), @@ -130,7 +144,7 @@ fn parse_function(item_fn: ItemFn, content: &str) -> Option { }) } -fn parse_struct(item_struct: ItemStruct, content: &str) -> Option { +fn parse_struct(item_struct: ItemStruct, _content: &str) -> Option { let start_line = item_struct.span().start().line; let end_line = item_struct.span().end().line; @@ -152,7 +166,7 @@ fn parse_struct(item_struct: ItemStruct, content: &str) -> Option { .generics .params .iter() - .map(|param| param.to_string()) + .map(generic_param_to_string) .collect(), traits: Vec::new(), fields, @@ -162,7 +176,7 @@ fn parse_struct(item_struct: ItemStruct, content: &str) -> Option { }) } -fn parse_enum(item_enum: ItemEnum, content: &str) -> Option { +fn parse_enum(item_enum: ItemEnum, _content: &str) -> Option { let start_line = item_enum.span().start().line; let end_line = item_enum.span().end().line; @@ -184,7 +198,7 @@ fn parse_enum(item_enum: ItemEnum, content: &str) -> Option { .generics .params .iter() - .map(|param| param.to_string()) + .map(generic_param_to_string) .collect(), traits: Vec::new(), fields: variants, @@ -194,7 +208,7 @@ fn parse_enum(item_enum: ItemEnum, content: &str) -> Option { }) } -fn parse_trait(item_trait: ItemTrait, content: &str) -> Option { +fn parse_trait(item_trait: ItemTrait, _content: &str) -> Option { let start_line = item_trait.span().start().line; let end_line = item_trait.span().end().line; @@ -222,7 +236,7 @@ fn parse_trait(item_trait: ItemTrait, content: &str) -> Option { .generics .params .iter() - .map(|param| param.to_string()) + .map(generic_param_to_string) .collect(), traits: Vec::new(), fields: Vec::new(), @@ -232,7 +246,7 @@ fn parse_trait(item_trait: ItemTrait, content: &str) -> Option { }) } -fn parse_impl(item_impl: ItemImpl, content: &str) -> Option { +fn parse_impl(item_impl: ItemImpl, _content: &str) -> Option { let start_line = item_impl.span().start().line; let end_line = item_impl.span().end().line; @@ -268,7 +282,7 @@ fn parse_impl(item_impl: ItemImpl, content: &str) -> Option { .generics .params .iter() - .map(|param| param.to_string()) + .map(generic_param_to_string) .collect(), traits, fields: Vec::new(), @@ -278,7 +292,7 @@ fn parse_impl(item_impl: ItemImpl, content: &str) -> Option { }) } -fn parse_mod(item_mod: syn::ItemMod, content: &str) -> Option { +fn parse_mod(item_mod: ItemMod, _content: &str) -> Option { let start_line = item_mod.span().start().line; let end_line = item_mod.span().end().line; @@ -307,9 +321,48 @@ fn visibility_to_string(vis: &Visibility) -> String { } fn type_to_string(ty: &Type) -> String { - format!("{}", quote::quote!(#ty)) + // Simple string representation for common types + match ty { + Type::Path(type_path) => type_path + .path + .segments + .last() + .map(|seg| seg.ident.to_string()) + .unwrap_or_else(|| "unknown".to_string()), + Type::Reference(type_ref) => { + format!("&{}", type_to_string(&type_ref.elem)) + } + _ => "unknown".to_string(), + } } fn path_to_string(path: &syn::Path) -> String { - format!("{}", quote::quote!(#path)) + path.segments + .iter() + .map(|seg| seg.ident.to_string()) + .collect::>() + .join("::") +} + +fn generic_param_to_string(param: &syn::GenericParam) -> String { + match param { + syn::GenericParam::Type(ty) => ty.ident.to_string(), + syn::GenericParam::Lifetime(lf) => lf.lifetime.to_string(), + syn::GenericParam::Const(cnst) => cnst.ident.to_string(), + } +} + +fn extract_doc_comment(attr: &syn::Attribute) -> Option { + if attr.path().is_ident("doc") { + if let syn::Meta::NameValue(meta) = &attr.meta { + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &meta.value + { + return Some(lit_str.value().trim().to_string()); + } + } + } + None }