conjure_cp_essence_parser/diagnostics/error_detection/
semantic_errors.rs

1// Basic syntactic error detection helpers for the LSP API.
2
3use crate::diagnostics::diagnostics_api::{Diagnostic, Position, Range, Severity};
4use crate::parse_essence_with_context;
5use conjure_cp_core::context::Context;
6use std::sync::{Arc, RwLock};
7
8/// Detects very simple semantic issues in source and returns a vector
9/// of Diagnostics.
10pub fn detect_semantic_errors(source: &str) -> Vec<Diagnostic> {
11    let mut diagnostics = Vec::new();
12    let context = Arc::new(RwLock::new(Context::default()));
13
14    match parse_essence_with_context(source, context) {
15        Ok(_model) => {
16            // no errors, all good
17            println!("No semantic errors detected");
18        }
19        Err(err) => {
20            println!("Semantic error detected: {:?}", err);
21            diagnostics.push(error_to_diagnostic(&err));
22        }
23    }
24
25    diagnostics
26}
27
28pub fn error_to_diagnostic(err: &crate::errors::EssenceParseError) -> Diagnostic {
29    match err {
30        crate::EssenceParseError::SyntaxError { msg, range } => {
31            let (start, end) = range_to_position(range);
32            Diagnostic {
33                range: Range { start, end },
34                severity: Severity::Error,
35                source: "semantic error detection",
36                message: format!("Semantic Error: {}", msg),
37            }
38        }
39        _ => Diagnostic {
40            range: Range {
41                start: Position {
42                    line: 0,
43                    character: 0,
44                },
45                end: Position {
46                    line: 0,
47                    character: 1,
48                },
49            },
50            severity: Severity::Error,
51            source: "semantic error detection",
52            message: format!("{}", err),
53        },
54    }
55}
56
57fn range_to_position(range: &Option<tree_sitter::Range>) -> (Position, Position) {
58    match range {
59        Some(r) => (
60            Position {
61                line: r.start_point.row as u32,
62                character: r.start_point.column as u32,
63            },
64            Position {
65                line: r.end_point.row as u32,
66                character: r.end_point.column as u32,
67            },
68        ),
69        None => (
70            Position {
71                line: 0,
72                character: 0,
73            },
74            Position {
75                line: 0,
76                character: 0,
77            },
78        ),
79    }
80}