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
pub 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

            
28
pub 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

            
57
fn 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
}