palladium/errors/
suggestions.rs1pub struct SuggestionEngine;
8
9impl SuggestionEngine {
10 pub fn suggest_similar_name(name: &str, available: &[String]) -> Option<String> {
12 let name_lower = name.to_lowercase();
13
14 for candidate in available {
16 if candidate.to_lowercase() == name_lower {
17 return Some(candidate.clone());
18 }
19 }
20
21 let mut best_match = None;
23 let mut best_distance = usize::MAX;
24
25 for candidate in available {
26 let distance = Self::edit_distance(name, candidate);
27
28 if distance < best_distance && distance <= name.len() / 3 + 1 {
30 best_distance = distance;
31 best_match = Some(candidate.clone());
32 }
33 }
34
35 best_match
36 }
37
38 fn edit_distance(a: &str, b: &str) -> usize {
40 let a_chars: Vec<char> = a.chars().collect();
41 let b_chars: Vec<char> = b.chars().collect();
42 let a_len = a_chars.len();
43 let b_len = b_chars.len();
44
45 if a_len == 0 {
46 return b_len;
47 }
48 if b_len == 0 {
49 return a_len;
50 }
51
52 let mut matrix = vec![vec![0; b_len + 1]; a_len + 1];
53
54 for (i, row) in matrix.iter_mut().enumerate().take(a_len + 1) {
56 row[0] = i;
57 }
58 for j in 0..=b_len {
59 matrix[0][j] = j;
60 }
61
62 for i in 1..=a_len {
64 for j in 1..=b_len {
65 let cost = if a_chars[i - 1] == b_chars[j - 1] {
66 0
67 } else {
68 1
69 };
70 matrix[i][j] = (matrix[i - 1][j] + 1) .min(matrix[i][j - 1] + 1) .min(matrix[i - 1][j - 1] + cost); }
74 }
75
76 matrix[a_len][b_len]
77 }
78
79 pub fn is_fancy_quote(ch: char) -> bool {
81 matches!(
82 ch,
83 '\u{201C}' | '\u{201D}' | '\u{2018}' | '\u{2019}' | '`' | '\u{00B4}'
84 )
85 }
86
87 pub fn suggest_ascii_quote(ch: char) -> Option<char> {
89 match ch {
90 '\u{201C}' | '\u{201D}' => Some('"'),
91 '\u{2018}' | '\u{2019}' | '`' | '\u{00B4}' => Some('\''),
92 _ => None,
93 }
94 }
95
96 pub fn suggest_for_c_style_mistake(code: &str) -> Option<String> {
98 if code.contains("++") {
99 Some(
100 "Palladium doesn't have ++ operator. Use 'x = x + 1' or 'x += 1' instead"
101 .to_string(),
102 )
103 } else if code.contains("--") {
104 Some(
105 "Palladium doesn't have -- operator. Use 'x = x - 1' or 'x -= 1' instead"
106 .to_string(),
107 )
108 } else if code.contains("==") && code.contains("=") {
109 Some("Make sure you're using '=' for assignment and '==' for comparison".to_string())
110 } else if code.starts_with("#include") {
111 Some(
112 "Palladium uses 'import' instead of '#include'. Example: import std.io;"
113 .to_string(),
114 )
115 } else if code.contains("malloc") || code.contains("free") {
116 Some(
117 "Palladium has automatic memory management. You don't need malloc/free".to_string(),
118 )
119 } else {
120 None
121 }
122 }
123
124 pub fn suggest_type_conversion(from_type: &str, to_type: &str) -> Option<String> {
126 match (
127 from_type.to_lowercase().as_str(),
128 to_type.to_lowercase().as_str(),
129 ) {
130 ("int" | "i64", "string") => {
131 Some("Use int_to_string() to convert int to string".to_string())
132 }
133 ("string", "int" | "i64") => {
134 Some("Use parse_int() to convert string to int".to_string())
135 }
136 ("float", "int" | "i64") => Some("Use to_int() to convert float to int".to_string()),
137 ("int" | "i64", "float") => Some("Use to_float() to convert int to float".to_string()),
138 ("bool", "string") => Some("Use to_string() to convert bool to string".to_string()),
139 ("string", "bool") => Some("Use parse_bool() to convert string to bool".to_string()),
140 _ => None,
141 }
142 }
143
144 pub fn suggest_import_for_function(func_name: &str) -> Option<String> {
146 match func_name {
147 "println" | "print" | "readln" => Some("import std.io;".to_string()),
148 "sqrt" | "pow" | "abs" | "sin" | "cos" => Some("import std.math;".to_string()),
149 "len" | "substr" | "concat" => Some("import std.string;".to_string()),
150 "Vec" | "HashMap" | "Set" => Some("import std.collections;".to_string()),
151 _ => None,
152 }
153 }
154
155 pub fn check_balanced_delimiters(code: &str) -> Option<String> {
157 let mut stack = Vec::new();
158
159 for (i, ch) in code.chars().enumerate() {
160 match ch {
161 '(' | '[' | '{' => stack.push((ch, i)),
162 ')' => {
163 if let Some((open, _)) = stack.pop() {
164 if open != '(' {
165 return Some(format!(
166 "Mismatched parentheses: expected '{}' to match '{}'",
167 Self::matching_delimiter(open),
168 open
169 ));
170 }
171 } else {
172 return Some("Unmatched closing parenthesis ')'".to_string());
173 }
174 }
175 ']' => {
176 if let Some((open, _)) = stack.pop() {
177 if open != '[' {
178 return Some(format!(
179 "Mismatched brackets: expected '{}' to match '{}'",
180 Self::matching_delimiter(open),
181 open
182 ));
183 }
184 } else {
185 return Some("Unmatched closing bracket ']'".to_string());
186 }
187 }
188 '}' => {
189 if let Some((open, _)) = stack.pop() {
190 if open != '{' {
191 return Some(format!(
192 "Mismatched braces: expected '{}' to match '{}'",
193 Self::matching_delimiter(open),
194 open
195 ));
196 }
197 } else {
198 return Some("Unmatched closing brace '}'".to_string());
199 }
200 }
201 _ => {}
202 }
203 }
204
205 if let Some((open, _)) = stack.pop() {
206 Some(format!(
207 "Unclosed delimiter '{}', expected '{}'",
208 open,
209 Self::matching_delimiter(open)
210 ))
211 } else {
212 None
213 }
214 }
215
216 fn matching_delimiter(open: char) -> char {
217 match open {
218 '(' => ')',
219 '[' => ']',
220 '{' => '}',
221 _ => open,
222 }
223 }
224}
225
226pub struct BeginnerPatterns;
228
229impl BeginnerPatterns {
230 pub fn check_pattern(code: &str) -> Vec<String> {
231 let mut suggestions = Vec::new();
232
233 if code.contains("%d") || code.contains("%s") || code.contains("%f") {
235 suggestions.push(
236 "Palladium uses string interpolation instead of printf-style formatting. \
237 Example: println(\"x = {}\", x);"
238 .to_string(),
239 );
240 }
241
242 if code.contains("null") || code.contains("nil") || code.contains("NULL") {
244 suggestions.push(
245 "Palladium uses Option types instead of null. \
246 Use 'Option<T>' and 'Some(value)' or 'None'"
247 .to_string(),
248 );
249 }
250
251 if code.contains("var ") {
253 suggestions.push(
254 "Palladium uses 'let' for variables and 'let mut' for mutable variables"
255 .to_string(),
256 );
257 }
258
259 if code.contains("const ") && !code.trim_start().starts_with("const") {
261 suggestions.push(
262 "In Palladium, 'const' should be used at the top level for constants".to_string(),
263 );
264 }
265
266 if code.contains("class ") {
268 suggestions.push(
269 "Palladium uses 'struct' for data types. Classes are not supported yet".to_string(),
270 );
271 }
272
273 if code.contains("switch") {
275 suggestions.push(
276 "Palladium uses 'match' expressions instead of switch statements".to_string(),
277 );
278 }
279
280 if code.contains("do {") || code.contains("do{") {
282 suggestions.push(
283 "Palladium doesn't have do-while loops. Use 'loop { ... if condition { break; } }'"
284 .to_string(),
285 );
286 }
287
288 suggestions
289 }
290}