eure_mark/
query.rs

1//! Query-flow queries for eure-mark.
2
3use std::sync::Arc;
4
5use eure::query::{ParseCst, ParseDocument, TextFile};
6use eure::report::{ErrorReports, Origin, format_error_reports};
7use eure_document::document::EureDocument;
8use eure_document::parse::ParseError;
9use eure_tree::prelude::Cst;
10use eure_tree::tree::InputSpan;
11use query_flow::{Db, QueryError, query};
12
13use crate::document::EumdDocument;
14use crate::report::EumdReportContext;
15use crate::{check_references_with_spans, report_check_errors};
16
17/// Parsed EumdDocument with CST and OriginMap for error reporting.
18#[derive(Clone, PartialEq)]
19pub struct ParsedEumd {
20    /// The parsed EumdDocument
21    pub doc: Arc<EumdDocument>,
22    /// The underlying EureDocument (for span resolution)
23    pub eure_doc: Arc<EureDocument>,
24    /// CST for error formatting
25    pub cst: Arc<Cst>,
26    /// Origin map for error formatting
27    pub origins: Arc<eure::document::OriginMap>,
28}
29
30/// Parse an EumdDocument from a file.
31///
32/// This query combines:
33/// - ParseDocument (which internally handles CST parsing)
34/// - EumdDocument parsing from the document
35///
36/// Returns errors via ErrorReports if parsing fails.
37#[query]
38pub fn parse_eumd_document(db: &impl Db, file: TextFile) -> Result<ParsedEumd, QueryError> {
39    // Parse the document
40    let parsed_doc = db.query(ParseDocument::new(file.clone()))?;
41
42    // Get CST for error formatting (cached from ParseDocument's internal call)
43    let parsed_cst = db.query(ParseCst::new(file.clone()))?;
44
45    // Parse EumdDocument from the document
46    let root_id = parsed_doc.doc.get_root_id();
47    let eumd_doc: EumdDocument = parsed_doc.doc.parse(root_id).map_err(|e: ParseError| {
48        // Convert parse error to ErrorReports
49        let span = parsed_doc
50            .origins
51            .get_value_span(e.node_id, &parsed_cst.cst)
52            .unwrap_or(InputSpan::EMPTY);
53        let origin = Origin::new(file.clone(), span);
54        ErrorReports::from(vec![eure::report::ErrorReport::error(
55            e.to_string(),
56            origin,
57        )])
58    })?;
59
60    Ok(ParsedEumd {
61        doc: Arc::new(eumd_doc),
62        eure_doc: parsed_doc.doc.clone(),
63        cst: Arc::new(parsed_cst.cst.clone()),
64        origins: parsed_doc.origins.clone(),
65    })
66}
67
68/// Check references in an EumdDocument and return errors.
69///
70/// This query combines:
71/// - ParseEumdDocument
72/// - Reference checking
73///
74/// Returns ErrorReports with any reference errors found.
75#[query]
76pub fn check_eumd_references(db: &impl Db, file: TextFile) -> Result<ErrorReports, QueryError> {
77    let parsed = db.query(ParseEumdDocument::new(file.clone()))?;
78
79    // Check references (explicit dereference for proper type coercion)
80    let result = check_references_with_spans(&parsed.doc, &parsed.eure_doc);
81
82    if result.is_ok() {
83        Ok(ErrorReports::new())
84    } else {
85        // Convert check errors to ErrorReports
86        let ctx = EumdReportContext {
87            file,
88            cst: &parsed.cst,
89            origins: &parsed.origins,
90        };
91        Ok(report_check_errors(&result, &ctx))
92    }
93}
94
95/// Check references in an EumdDocument and return formatted error strings.
96///
97/// This query combines:
98/// - CheckEumdReferences
99/// - Error formatting
100///
101/// Returns formatted error strings for each reference error found.
102#[query]
103pub fn check_eumd_references_formatted(
104    db: &impl Db,
105    file: TextFile,
106) -> Result<Vec<String>, QueryError> {
107    let reports = db.query(CheckEumdReferences::new(file))?;
108
109    // Format each error individually
110    let mut formatted = Vec::new();
111    for r in reports.iter() {
112        let single = ErrorReports::from(vec![r.clone()]);
113        let s = format_error_reports(db, &single, false)?;
114        formatted.push(s.trim().to_string());
115    }
116    Ok(formatted)
117}