1use std::{
2 collections::{HashMap, HashSet},
3 sync::Arc,
4};
5
6use bevy_ecs::{prelude::*, world::World};
7use completion::{CompletionRequest, SimpleCompletion};
8use rdf_parsers::{IncrementalBias, PrevParseInfo};
9use rowan::NodeOrToken;
10use sophia_api::{
11 quad::Quad as _,
12 term::{Term as _, TermKind},
13};
14use swls_core::{
15 components::*,
16 lsp_types::CompletionItemKind,
17 prelude::*,
18};
19use swls_lang_rdf_base::traits::{NamedNodeExt, TurtleExt};
20
21use crate::Sparql;
22
23pub fn setup_parse(world: &mut World) {
24 use swls_core::feature::parse::*;
25 world.schedule_scope(Label, |_, schedule| {
26 schedule.add_systems((
27 parse_sparql_system,
28 derive_triples
29 .after(parse_sparql_system)
30 .before(prefixes)
31 .before(triples),
32 ));
33 });
34}
35
36pub fn setup_completion(world: &mut World) {
37 use swls_core::feature::completion::*;
38 world.schedule_scope(Label, |_, schedule| {
39 schedule.add_systems((
40 variable_completion.after(generate_completions),
41 ));
42 });
43}
44
45fn extract_sparql_cst_tokens(
46 node: &rowan::SyntaxNode<rdf_parsers::sparql::parser::Lang>,
47) -> Vec<swls_core::prelude::Spanned<rowan::SyntaxKind>> {
48 use rdf_parsers::sparql::parser::SyntaxKind;
49 let mut tokens = Vec::new();
50 for node_or_token in node.descendants_with_tokens() {
51 if let NodeOrToken::Token(t) = node_or_token {
52 let kind = t.kind();
53 if kind == SyntaxKind::WhiteSpace {
54 continue;
55 }
56 let range = t.text_range();
57 let span = usize::from(range.start())..usize::from(range.end());
58 tokens.push(swls_core::prelude::spanned(
59 rowan::SyntaxKind(kind as u16),
60 span,
61 ));
62 }
63 }
64 tokens
65}
66
67#[instrument(skip(query, commands, prev_infos, config))]
68fn parse_sparql_system(
69 query: Query<(Entity, &Source, &Label), (Changed<Source>, With<Sparql>)>,
70 mut commands: Commands,
71 mut prev_infos: Local<HashMap<String, PrevParseInfo>>,
72 config: Res<ServerConfig>,
73) {
74 if !config.config.sparql.unwrap_or(true) {
75 return;
76 }
77 for (entity, source, label) in &query {
78 use rdf_parsers::sparql::{
79 convert::convert,
80 parser::{Lang, Rule, SyntaxKind},
81 };
82
83 let prev = prev_infos.get(label.as_str());
84 let (parse, new_prev) = rdf_parsers::parse_incremental(
85 Rule::new(SyntaxKind::QueryUnit),
86 source.0.as_str(),
87 prev,
88 IncrementalBias::default(),
89 );
90 prev_infos.insert(label.to_string(), new_prev);
91
92 let syntax = parse.syntax::<Lang>();
93 let errors = collect_errors(&syntax);
94 let mut turtle_model = convert(&syntax);
95 turtle_model.set_base = Some(label.to_string());
96
97 let cst_tokens = extract_sparql_cst_tokens(&syntax);
98
99 let span = 0..source.0.len();
100 let element = Element(swls_core::prelude::spanned(turtle_model, span));
101
102 if errors.is_empty() {
103 commands
104 .entity(entity)
105 .insert((element, Errors(errors), CstTokens(cst_tokens)))
106 .remove::<Dirty>();
107 } else {
108 commands
109 .entity(entity)
110 .insert((element, Errors(errors), CstTokens(cst_tokens), Dirty));
111 }
112 }
113}
114
115fn collect_errors(
116 node: &rowan::SyntaxNode<rdf_parsers::sparql::parser::Lang>,
117) -> Vec<swls_lang_turtle::lang::parser::TurtleParseError> {
118 use rdf_parsers::sparql::parser::SyntaxKind;
119 use swls_lang_turtle::lang::parser::TurtleParseError;
120
121 let mut errors = Vec::new();
122 let mut stack = vec![node.clone()];
123 while let Some(current) = stack.pop() {
124 for child in current.children_with_tokens() {
125 match child {
126 NodeOrToken::Node(n) => {
127 if n.kind() == SyntaxKind::Error {
128 let range = rdf_parsers::effective_error_span::<
129 rdf_parsers::sparql::parser::Lang,
130 >(&n);
131 let msg = n
132 .parent()
133 .map(|p| format!("Expected: {:?}", p.kind()))
134 .unwrap_or_else(|| format!("Unexpected: {}", n.text()));
135 errors.push(TurtleParseError { range, msg });
136 } else {
137 stack.push(n);
138 }
139 }
140 NodeOrToken::Token(t) => {
141 if t.kind() == SyntaxKind::Error {
142 let r = t.text_range();
143 errors.push(TurtleParseError {
144 range: r.start().into()..r.end().into(),
145 msg: format!("Unexpected: {}", t.text()),
146 });
147 }
148 }
149 }
150 }
151 }
152 errors
153}
154
155#[instrument(skip(query, commands))]
156fn derive_triples(
157 query: Query<(Entity, &Label, &Element), (Changed<Element>, With<Sparql>)>,
158 mut commands: Commands,
159) {
160 for (entity, label, el) in &query {
161 let turtle = el.0.value();
162
163 let prefixes: Vec<_> = turtle
164 .prefixes
165 .iter()
166 .flat_map(|prefix| {
167 let url = prefix.value().value.expand(turtle)?;
168 let url = swls_core::lsp_types::Url::parse(&url).ok()?;
169 Some(Prefix {
170 url,
171 prefix: prefix.value().prefix.value().clone(),
172 })
173 })
174 .collect();
175
176 commands
177 .entity(entity)
178 .insert(Prefixes(prefixes, label.0.clone()));
179
180 match el.0.get_simple_triples() {
181 Ok(triples) => {
182 let triples: Vec<_> = triples.iter().map(|x| x.to_owned()).collect();
183 commands.entity(entity).insert(Triples(Arc::new(triples)));
184 }
185 Err(e) => {
186 tracing::warn!("derive_triples error for {}: {:?}", label.as_str(), e);
187 }
188 }
189 }
190}
191
192#[instrument(skip(query))]
193pub fn variable_completion(
194 mut query: Query<(&Triples, &TokenComponent, &mut CompletionRequest), With<Sparql>>,
195) {
196 for (triples, token, mut req) in &mut query {
197 if token.text.starts_with('?') {
198 let var_set: HashSet<_> = triples
199 .0
200 .iter()
201 .flat_map(|q| [q.s(), q.p(), q.o()])
202 .filter(|t| t.kind() == TermKind::Variable)
203 .map(|t| t.value.clone())
204 .collect();
205
206 for name in var_set {
207 let t = format!("?{}", name);
208 let completion = SimpleCompletion::new(
209 CompletionItemKind::VARIABLE,
210 t.clone(),
211 swls_core::lsp_types::TextEdit {
212 range: token.range.clone(),
213 new_text: t,
214 },
215 );
216 req.push(completion);
217 }
218 }
219 }
220}