makefile_lossless/ast/
archive.rs1use crate::lossless::{ArchiveMember, ArchiveMembers};
2use crate::SyntaxKind::*;
3use rowan::ast::AstNode;
4
5impl ArchiveMembers {
6 pub fn archive_name(&self) -> Option<String> {
8 for element in self.syntax().children_with_tokens() {
10 if let Some(token) = element.as_token() {
11 if token.kind() == IDENTIFIER {
12 return Some(token.text().to_string());
13 } else if token.kind() == LPAREN {
14 break;
16 }
17 }
18 }
19 None
20 }
21
22 pub fn members(&self) -> impl Iterator<Item = ArchiveMember> + '_ {
24 self.syntax().children().filter_map(ArchiveMember::cast)
25 }
26
27 pub fn member_names(&self) -> Vec<String> {
29 self.members().map(|m| m.text()).collect()
30 }
31}
32
33impl ArchiveMember {
34 pub fn text(&self) -> String {
36 self.syntax().text().to_string().trim().to_string()
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::lossless::parse;
44 use crate::SyntaxKind::ARCHIVE_MEMBERS;
45
46 #[test]
47 fn test_archive_member_parsing() {
48 let input = "libfoo.a(bar.o): bar.c\n\tgcc -c bar.c -o bar.o\n\tar r libfoo.a bar.o\n";
50 let parsed = parse(input, None);
51 assert!(
52 parsed.errors.is_empty(),
53 "Should parse archive member without errors"
54 );
55
56 let makefile = parsed.root();
57 let rules: Vec<_> = makefile.rules().collect();
58 assert_eq!(rules.len(), 1);
59
60 let target_text = rules[0].targets().next().unwrap();
62 assert_eq!(target_text, "libfoo.a(bar.o)");
63 }
64
65 #[test]
66 fn test_archive_member_multiple_members() {
67 let input = "libfoo.a(bar.o baz.o): bar.c baz.c\n\tgcc -c bar.c baz.c\n\tar r libfoo.a bar.o baz.o\n";
69 let parsed = parse(input, None);
70 assert!(
71 parsed.errors.is_empty(),
72 "Should parse multiple archive members"
73 );
74
75 let makefile = parsed.root();
76 let rules: Vec<_> = makefile.rules().collect();
77 assert_eq!(rules.len(), 1);
78 }
79
80 #[test]
81 fn test_archive_member_in_dependencies() {
82 let input =
84 "program: main.o libfoo.a(bar.o) libfoo.a(baz.o)\n\tgcc -o program main.o libfoo.a\n";
85 let parsed = parse(input, None);
86 assert!(
87 parsed.errors.is_empty(),
88 "Should parse archive members in dependencies"
89 );
90
91 let makefile = parsed.root();
92 let rules: Vec<_> = makefile.rules().collect();
93 assert_eq!(rules.len(), 1);
94 }
95
96 #[test]
97 fn test_archive_member_with_variables() {
98 let input = "$(LIB)($(OBJ)): $(SRC)\n\t$(CC) -c $(SRC)\n\t$(AR) r $(LIB) $(OBJ)\n";
100 let parsed = parse(input, None);
101 assert!(
103 parsed.errors.is_empty(),
104 "Should parse archive members with variables"
105 );
106 }
107
108 #[test]
109 fn test_archive_member_ast_access() {
110 let input = "libtest.a(foo.o bar.o): foo.c bar.c\n\tgcc -c foo.c bar.c\n";
112 let parsed = parse(input, None);
113 let makefile = parsed.root();
114
115 let archive_member_count = makefile
117 .syntax()
118 .descendants()
119 .filter(|n| n.kind() == ARCHIVE_MEMBERS)
120 .count();
121
122 assert!(
123 archive_member_count > 0,
124 "Should find ARCHIVE_MEMBERS nodes in AST"
125 );
126 }
127}