1use std::collections::HashMap;
6use std::path::PathBuf;
7
8use crate::ast::{SourceLocation, UnionDef, WordDef};
9
10pub fn check_collisions(words: &[WordDef]) -> Result<(), String> {
11 let mut definitions: HashMap<&str, Vec<&SourceLocation>> = HashMap::new();
12
13 for word in words {
14 if let Some(ref source) = word.source {
15 definitions.entry(&word.name).or_default().push(source);
16 }
17 }
18
19 let mut errors = Vec::new();
21 for (name, locations) in definitions {
22 if locations.len() > 1 {
23 let mut msg = format!("Word '{}' is defined multiple times:\n", name);
24 for loc in &locations {
25 msg.push_str(&format!(" - {}\n", loc));
26 }
27 msg.push_str("\nHint: Rename one of the definitions to avoid collision.");
28 errors.push(msg);
29 }
30 }
31
32 if errors.is_empty() {
33 Ok(())
34 } else {
35 Err(errors.join("\n\n"))
36 }
37}
38
39pub fn check_union_collisions(unions: &[UnionDef]) -> Result<(), String> {
43 let mut definitions: HashMap<&str, Vec<&SourceLocation>> = HashMap::new();
44
45 for union_def in unions {
46 if let Some(ref source) = union_def.source {
47 definitions.entry(&union_def.name).or_default().push(source);
48 }
49 }
50
51 let mut errors = Vec::new();
53 for (name, locations) in definitions {
54 if locations.len() > 1 {
55 let mut msg = format!("Union '{}' is defined multiple times:\n", name);
56 for loc in &locations {
57 msg.push_str(&format!(" - {}\n", loc));
58 }
59 msg.push_str("\nHint: Rename one of the definitions to avoid collision.");
60 errors.push(msg);
61 }
62 }
63
64 if errors.is_empty() {
65 Ok(())
66 } else {
67 Err(errors.join("\n\n"))
68 }
69}
70
71pub fn find_stdlib() -> Option<PathBuf> {
80 if let Ok(path) = std::env::var("SEQ_STDLIB") {
82 let path = PathBuf::from(path);
83 if path.is_dir() {
84 return Some(path);
85 }
86 eprintln!(
88 "Warning: SEQ_STDLIB is set to '{}' but that directory doesn't exist",
89 path.display()
90 );
91 }
92
93 if let Ok(exe_path) = std::env::current_exe()
95 && let Some(exe_dir) = exe_path.parent()
96 {
97 let stdlib_path = exe_dir.join("stdlib");
98 if stdlib_path.is_dir() {
99 return Some(stdlib_path);
100 }
101 if let Some(parent) = exe_dir.parent() {
103 let stdlib_path = parent.join("stdlib");
104 if stdlib_path.is_dir() {
105 return Some(stdlib_path);
106 }
107 }
108 }
109
110 let local_stdlib = PathBuf::from("stdlib");
112 if local_stdlib.is_dir() {
113 return Some(local_stdlib.canonicalize().unwrap_or(local_stdlib));
114 }
115
116 None
118}