1
// Basic syntactic error detection helpers for the LSP API.
2

            
3
use crate::diagnostics::diagnostics_api::{Diagnostic, Position, Range, Severity};
4
use crate::errors::RecoverableParseError;
5
use crate::parse_essence_with_context_and_map;
6
use conjure_cp_core::context::Context;
7
use std::sync::{Arc, RwLock};
8
use tree_sitter::Tree;
9

            
10
468
pub fn detect_errors(source: &str, cst: &Tree) -> Vec<Diagnostic> {
11
468
    let mut diagnostics: Vec<Diagnostic> = Vec::new();
12
468
    let mut errors: Vec<RecoverableParseError> = vec![];
13
468
    let context = Arc::new(RwLock::new(Context::default()));
14

            
15
468
    let _ = parse_essence_with_context_and_map(source, context, &mut errors, Some(cst));
16

            
17
481
    diagnostics.extend(errors.into_iter().map(|e| error_to_diagnostic(&e)));
18

            
19
468
    diagnostics
20
468
}
21

            
22
481
pub fn error_to_diagnostic(err: &RecoverableParseError) -> Diagnostic {
23
481
    let (start, end) = range_to_position(&err.range);
24
481
    Diagnostic {
25
481
        range: Range { start, end },
26
481
        severity: Severity::Error,
27
481
        source: "semantic error detection",
28
481
        message: err.msg.clone(),
29
481
    }
30
481
}
31

            
32
481
fn range_to_position(range: &Option<tree_sitter::Range>) -> (Position, Position) {
33
481
    match range {
34
481
        Some(r) => (
35
481
            Position {
36
481
                line: r.start_point.row as u32,
37
481
                character: r.start_point.column as u32,
38
481
            },
39
481
            Position {
40
481
                line: r.end_point.row as u32,
41
481
                character: r.end_point.column as u32,
42
481
            },
43
481
        ),
44
        None => (
45
            Position {
46
                line: 0,
47
                character: 0,
48
            },
49
            Position {
50
                line: 0,
51
                character: 0,
52
            },
53
        ),
54
    }
55
481
}
56

            
57
/// Helper function for tests to compare the actual diagnostic with the expected one.
58
481
pub fn check_diagnostic(
59
481
    diag: &Diagnostic,
60
481
    line_start: u32,
61
481
    char_start: u32,
62
481
    line_end: u32,
63
481
    char_end: u32,
64
481
    msg: &str,
65
481
) {
66
    // Checking range
67
481
    assert_eq!(diag.range.start.line, line_start);
68
481
    assert_eq!(diag.range.start.character, char_start);
69
481
    assert_eq!(diag.range.end.line, line_end);
70
481
    assert_eq!(diag.range.end.character, char_end);
71

            
72
    // Check the message
73
481
    assert_eq!(diag.message, msg);
74
481
}