1use slang_error::{CompilerError, ErrorCode};
2use slang_ir::Location;
3use slang_shared::CompilationContext;
4use slang_types::TypeId;
5
6#[derive(Debug, Clone)]
12pub enum SemanticAnalysisError {
13 UndefinedVariable {
15 name: String,
17 location: Location,
19 },
20
21 VariableRedefinition {
23 name: String,
25 location: Location,
27 },
28
29 SymbolRedefinition {
31 name: String,
33 kind: String,
35 location: Location,
37 },
38
39 InvalidFieldType {
41 struct_name: String,
43 field_name: String,
45 type_id: TypeId,
47 location: Location,
49 },
50
51 TypeMismatch {
53 expected: TypeId,
55 actual: TypeId,
57 context: Option<String>,
59 location: Location,
61 },
62
63 OperationTypeMismatch {
65 operator: String,
67 left_type: TypeId,
69 right_type: TypeId,
71 location: Location,
73 },
74
75 LogicalOperatorTypeMismatch {
77 operator: String,
79 left_type: TypeId,
81 right_type: TypeId,
83 location: Location,
85 },
86
87 ValueOutOfRange {
89 value: String,
91 target_type: TypeId,
93 is_float: bool,
95 location: Location,
97 },
98
99 ArgumentCountMismatch {
101 function_name: String,
103 expected: usize,
105 actual: usize,
107 location: Location,
109 },
110
111 ArgumentTypeMismatch {
113 function_name: String,
115 argument_position: usize,
117 expected: TypeId,
119 actual: TypeId,
121 location: Location,
123 },
124
125 ReturnOutsideFunction {
127 location: Location,
129 },
130
131 ReturnTypeMismatch {
133 expected: TypeId,
135 actual: TypeId,
137 location: Location,
139 },
140
141 MissingReturnValue {
143 expected: TypeId,
145 location: Location,
147 },
148
149 UndefinedFunction {
151 name: String,
153 location: Location,
155 },
156
157 InvalidUnaryOperation {
159 operator: String,
161 operand_type: TypeId,
163 location: Location,
165 },
166
167 AssignmentToImmutableVariable {
169 name: String,
171 location: Location,
173 },
174
175 InvalidExpression {
177 message: String,
179 location: Location,
181 },
182
183 VariableNotCallable {
185 variable_name: String,
187 variable_type: TypeId,
189 location: Location,
191 },
192}
193
194impl SemanticAnalysisError {
195 pub fn format_message(&self, context: &CompilationContext) -> String {
198 match self {
199 SemanticAnalysisError::UndefinedVariable { name, .. } => {
200 format!("Undefined variable: {}", name)
201 }
202
203 SemanticAnalysisError::VariableRedefinition { name, .. } => {
204 format!("Variable '{}' already defined", name)
205 }
206
207 SemanticAnalysisError::SymbolRedefinition { name, kind, .. } => match kind.as_str() {
208 "function" => format!(
209 "Function '{}' is already defined in the current scope.",
210 name
211 ),
212 "variable" => format!(
213 "Variable '{}' is already defined in the current scope.",
214 name
215 ),
216 "type" => format!("Type '{}' is already defined in the current scope.", name),
217 "parameter" => format!(
218 "Parameter '{}' is already defined in the current scope.",
219 name
220 ),
221 "variable (conflicts with type)" => format!(
222 "Symbol '{}' of kind 'variable (conflicts with type)' is already defined or conflicts with an existing symbol.",
223 name
224 ),
225 "variable (conflicts with function)" => format!(
226 "Symbol '{}' of kind 'variable (conflicts with function)' is already defined or conflicts with an existing symbol.",
227 name
228 ),
229 _ => format!("Symbol '{}' is already defined in the current scope.", name),
230 },
231
232 SemanticAnalysisError::InvalidFieldType {
233 struct_name,
234 field_name,
235 type_id,
236 ..
237 } => {
238 format!(
239 "Invalid type '{}' for field '{}' in struct '{}'. Fields cannot be of unknown or unspecified type.",
240 context.get_type_name(type_id),
241 field_name,
242 struct_name
243 )
244 }
245
246 SemanticAnalysisError::TypeMismatch {
247 expected,
248 actual,
249 context: error_context,
250 ..
251 } => {
252 if let Some(ctx) = error_context {
253 format!(
254 "Type mismatch: variable {} is {} but expression is {}",
255 ctx,
256 context.get_type_name(expected),
257 context.get_type_name(actual)
258 )
259 } else {
260 format!(
261 "Type mismatch: expected {}, got {}",
262 context.get_type_name(expected),
263 context.get_type_name(actual)
264 )
265 }
266 }
267
268 SemanticAnalysisError::OperationTypeMismatch {
269 operator,
270 left_type,
271 right_type,
272 ..
273 } => {
274 format!(
275 "Type mismatch: cannot apply '{}' operator on {} and {}",
276 operator,
277 context.get_type_name(left_type),
278 context.get_type_name(right_type)
279 )
280 }
281
282 SemanticAnalysisError::LogicalOperatorTypeMismatch {
283 operator,
284 left_type,
285 right_type,
286 ..
287 } => {
288 format!(
289 "Logical operator '{}' requires boolean operands, got {} and {}",
290 operator,
291 context.get_type_name(left_type),
292 context.get_type_name(right_type)
293 )
294 }
295
296 SemanticAnalysisError::ValueOutOfRange {
297 value,
298 target_type,
299 is_float,
300 ..
301 } => {
302 if *is_float {
303 format!(
304 "Float literal {} is out of range for type {}",
305 value,
306 context.get_type_name(target_type)
307 )
308 } else {
309 format!(
310 "Integer literal {} is out of range for type {}",
311 value,
312 context.get_type_name(target_type)
313 )
314 }
315 }
316
317 SemanticAnalysisError::ArgumentCountMismatch {
318 function_name,
319 expected,
320 actual,
321 ..
322 } => {
323 format!(
324 "Function '{}' expects {} arguments, but got {}",
325 function_name, expected, actual
326 )
327 }
328
329 SemanticAnalysisError::ArgumentTypeMismatch {
330 function_name,
331 argument_position,
332 expected,
333 actual,
334 ..
335 } => {
336 format!(
337 "Type mismatch: function '{}' expects argument {} to be {}, but got {}",
338 function_name,
339 argument_position,
340 context.get_type_name(expected),
341 context.get_type_name(actual)
342 )
343 }
344
345 SemanticAnalysisError::ReturnOutsideFunction { .. } => {
346 "Return statement outside of function".to_string()
347 }
348
349 SemanticAnalysisError::ReturnTypeMismatch {
350 expected, actual, ..
351 } => {
352 format!(
353 "Type mismatch: function returns {} but got {}",
354 context.get_type_name(expected),
355 context.get_type_name(actual)
356 )
357 }
358
359 SemanticAnalysisError::MissingReturnValue { expected, .. } => {
360 format!(
361 "Type mismatch: function returns {} but no return value provided",
362 context.get_type_name(expected)
363 )
364 }
365
366 SemanticAnalysisError::UndefinedFunction { name, .. } => {
367 format!("Undefined function: {}", name)
368 }
369
370 SemanticAnalysisError::InvalidUnaryOperation {
371 operator,
372 operand_type,
373 ..
374 } => {
375 if operator == "!" {
376 format!(
377 "Boolean not operator '!' can only be applied to boolean types, but got {}",
378 context.get_type_name(operand_type)
379 )
380 } else if operator == "-" {
381 if context.get_type_name(operand_type) == "u32"
382 || context.get_type_name(operand_type) == "u64"
383 {
384 "Cannot negate unsigned type".to_string()
385 } else {
386 format!(
387 "Cannot negate non-numeric type '{}'",
388 context.get_type_name(operand_type)
389 )
390 }
391 } else {
392 format!(
393 "Cannot apply operator '{}' to type {}",
394 operator,
395 context.get_type_name(operand_type)
396 )
397 }
398 }
399
400 SemanticAnalysisError::AssignmentToImmutableVariable { name, .. } => {
401 format!("Cannot assign to immutable variable '{}'", name)
402 }
403
404 SemanticAnalysisError::InvalidExpression { message, .. } => message.clone(),
405
406 SemanticAnalysisError::VariableNotCallable {
407 variable_name,
408 variable_type,
409 ..
410 } => {
411 format!(
412 "Cannot call {} type '{}' as a function",
413 context.get_type_name(variable_type),
414 variable_name
415 )
416 }
417 }
418 }
419
420 fn get_location(&self) -> &Location {
422 match self {
423 SemanticAnalysisError::UndefinedVariable { location, .. } => location,
424 SemanticAnalysisError::VariableRedefinition { location, .. } => location,
425 SemanticAnalysisError::SymbolRedefinition { location, .. } => location,
426 SemanticAnalysisError::InvalidFieldType { location, .. } => location,
427 SemanticAnalysisError::TypeMismatch { location, .. } => location,
428 SemanticAnalysisError::OperationTypeMismatch { location, .. } => location,
429 SemanticAnalysisError::LogicalOperatorTypeMismatch { location, .. } => location,
430 SemanticAnalysisError::ValueOutOfRange { location, .. } => location,
431 SemanticAnalysisError::ArgumentCountMismatch { location, .. } => location,
432 SemanticAnalysisError::ArgumentTypeMismatch { location, .. } => location,
433 SemanticAnalysisError::ReturnOutsideFunction { location, .. } => location,
434 SemanticAnalysisError::ReturnTypeMismatch { location, .. } => location,
435 SemanticAnalysisError::MissingReturnValue { location, .. } => location,
436 SemanticAnalysisError::UndefinedFunction { location, .. } => location,
437 SemanticAnalysisError::InvalidUnaryOperation { location, .. } => location,
438 SemanticAnalysisError::AssignmentToImmutableVariable { location, .. } => location,
439 SemanticAnalysisError::InvalidExpression { location, .. } => location,
440 SemanticAnalysisError::VariableNotCallable { location, .. } => location,
441 }
442 }
443
444 fn get_token_length(&self) -> Option<usize> {
447 let location = self.get_location();
448 return Some(location.length);
449 }
450
451 pub fn to_compiler_error(&self, context: &CompilationContext) -> CompilerError {
459 let location = self.get_location();
460 let token_length = self.get_token_length();
461 CompilerError::new(
462 self.error_code(),
463 self.format_message(context),
464 location.line,
465 location.column,
466 location.position,
467 token_length,
468 )
469 }
470
471 pub fn error_code(&self) -> ErrorCode {
473 match self {
474 SemanticAnalysisError::UndefinedVariable { .. } => ErrorCode::UndefinedVariable,
475 SemanticAnalysisError::VariableRedefinition { .. } => ErrorCode::VariableRedefinition,
476 SemanticAnalysisError::SymbolRedefinition { .. } => ErrorCode::SymbolRedefinition,
477 SemanticAnalysisError::InvalidFieldType { .. } => ErrorCode::InvalidFieldType,
478 SemanticAnalysisError::TypeMismatch { .. } => ErrorCode::TypeMismatch,
479 SemanticAnalysisError::OperationTypeMismatch { .. } => ErrorCode::OperationTypeMismatch,
480 SemanticAnalysisError::LogicalOperatorTypeMismatch { .. } => {
481 ErrorCode::LogicalOperatorTypeMismatch
482 }
483 SemanticAnalysisError::ValueOutOfRange { .. } => ErrorCode::ValueOutOfRange,
484 SemanticAnalysisError::ArgumentCountMismatch { .. } => ErrorCode::ArgumentCountMismatch,
485 SemanticAnalysisError::ArgumentTypeMismatch { .. } => ErrorCode::ArgumentTypeMismatch,
486 SemanticAnalysisError::ReturnOutsideFunction { .. } => ErrorCode::ReturnOutsideFunction,
487 SemanticAnalysisError::ReturnTypeMismatch { .. } => ErrorCode::ReturnTypeMismatch,
488 SemanticAnalysisError::MissingReturnValue { .. } => ErrorCode::MissingReturnValue,
489 SemanticAnalysisError::UndefinedFunction { .. } => ErrorCode::UndefinedFunction,
490 SemanticAnalysisError::InvalidUnaryOperation { .. } => ErrorCode::InvalidUnaryOperation,
491 SemanticAnalysisError::AssignmentToImmutableVariable { .. } => {
492 ErrorCode::AssignmentToImmutableVariable
493 }
494 SemanticAnalysisError::InvalidExpression { .. } => ErrorCode::InvalidExpression,
495 SemanticAnalysisError::VariableNotCallable { .. } => ErrorCode::VariableNotCallable,
496 }
497 }
498}