Skip to main content

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        }
18        Err(err) => {
19            diagnostics.push(error_to_diagnostic(&err));
20        }
21    }
22
23    diagnostics
24}
25
26pub fn error_to_diagnostic(err: &crate::errors::EssenceParseError) -> Diagnostic {
27    match err {
28        crate::EssenceParseError::SyntaxError { msg, range } => {
29            let (start, end) = range_to_position(range);
30            Diagnostic {
31                range: Range { start, end },
32                severity: Severity::Error,
33                source: "semantic error detection",
34                message: format!("Semantic Error: {}", msg),
35            }
36        }
37        _ => Diagnostic {
38            range: Range {
39                start: Position {
40                    line: 0,
41                    character: 0,
42                },
43                end: Position {
44                    line: 0,
45                    character: 1,
46                },
47            },
48            severity: Severity::Error,
49            source: "semantic error detection",
50            message: format!("{}", err),
51        },
52    }
53}
54
55fn range_to_position(range: &Option<tree_sitter::Range>) -> (Position, Position) {
56    match range {
57        Some(r) => (
58            Position {
59                line: r.start_point.row as u32,
60                character: r.start_point.column as u32,
61            },
62            Position {
63                line: r.end_point.row as u32,
64                character: r.end_point.column as u32,
65            },
66        ),
67        None => (
68            Position {
69                line: 0,
70                character: 0,
71            },
72            Position {
73                line: 0,
74                character: 0,
75            },
76        ),
77    }
78}