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

            
3
use crate::diagnostics::diagnostics_api::{Diagnostic, Position, Range, Severity};
4
use crate::parse_essence_with_context;
5
use conjure_cp_core::context::Context;
6
use std::sync::{Arc, RwLock};
7

            
8
/// Detects very simple semantic issues in source and returns a vector
9
/// of Diagnostics.
10
66
pub fn detect_semantic_errors(source: &str) -> Vec<Diagnostic> {
11
66
    let mut diagnostics = Vec::new();
12
66
    let context = Arc::new(RwLock::new(Context::default()));
13

            
14
66
    match parse_essence_with_context(source, context) {
15
11
        Ok(_model) => {
16
            // no errors, all good
17
11
        }
18
55
        Err(err) => {
19
55
            diagnostics.push(error_to_diagnostic(&err));
20
55
        }
21
    }
22

            
23
66
    diagnostics
24
66
}
25

            
26
55
pub fn error_to_diagnostic(err: &crate::errors::EssenceParseError) -> Diagnostic {
27
55
    match err {
28
55
        crate::EssenceParseError::SyntaxError { msg, range } => {
29
55
            let (start, end) = range_to_position(range);
30
55
            Diagnostic {
31
55
                range: Range { start, end },
32
55
                severity: Severity::Error,
33
55
                source: "semantic error detection",
34
55
                message: format!("Semantic Error: {}", msg),
35
55
            }
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
55
}
54

            
55
55
fn range_to_position(range: &Option<tree_sitter::Range>) -> (Position, Position) {
56
55
    match range {
57
55
        Some(r) => (
58
55
            Position {
59
55
                line: r.start_point.row as u32,
60
55
                character: r.start_point.column as u32,
61
55
            },
62
55
            Position {
63
55
                line: r.end_point.row as u32,
64
55
                character: r.end_point.column as u32,
65
55
            },
66
55
        ),
67
        None => (
68
            Position {
69
                line: 0,
70
                character: 0,
71
            },
72
            Position {
73
                line: 0,
74
                character: 0,
75
            },
76
        ),
77
    }
78
55
}