+12
CHANGELOG.md
+12
CHANGELOG.md
···
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8
+
## v0.10.4 -- 2023-06-02
9
+
10
+
### Library
11
+
12
+
#### Added
13
+
14
+
- Several errors include more context in the error message: Duplicate errors report both statements using source snippets. Edge statements report which argument (the source or the sink) triggered an evluation error.
15
+
16
+
#### Fixed
17
+
18
+
- Ensure that edge attribute statements are executed after edges are created, to prevent non-deterministic ordering bugs in lazy execution mode.
19
+
20
## v0.10.3 -- 2023-06-01
21
22
### DSL
+1
-1
Cargo.toml
+1
-1
Cargo.toml
+4
-6
src/execution/lazy.rs
+4
-6
src/execution/lazy.rs
···
65
let mut locals = VariableMap::new();
66
let mut store = LazyStore::new();
67
let mut scoped_store = LazyScopedVariables::new();
68
-
let mut lazy_graph = Vec::new();
69
let mut function_parameters = Vec::new();
70
let mut prev_element_debug_info = HashMap::new();
71
···
99
prev_element_debug_info: &mut prev_element_debug_info,
100
cancellation_flag,
101
};
102
-
for graph_stmt in &lazy_graph {
103
-
graph_stmt.evaluate(&mut exec)?;
104
-
}
105
// make sure any unforced values are now forced, to surface any problems
106
// hidden by the fact that the values were unused
107
store.evaluate_all(&mut exec)?;
···
140
mat: &'a QueryMatch<'a, 'tree>,
141
store: &'a mut LazyStore,
142
scoped_store: &'a mut LazyScopedVariables,
143
-
lazy_graph: &'a mut Vec<LazyStatement>,
144
function_parameters: &'a mut Vec<graph::Value>, // re-usable buffer to reduce memory allocations
145
prev_element_debug_info: &'a mut HashMap<GraphElementKey, DebugInfo>,
146
error_context: StatementContext,
···
179
locals: &mut VariableMap<'l, LazyValue>,
180
store: &mut LazyStore,
181
scoped_store: &mut LazyScopedVariables,
182
-
lazy_graph: &mut Vec<LazyStatement>,
183
function_parameters: &mut Vec<graph::Value>,
184
prev_element_debug_info: &mut HashMap<GraphElementKey, DebugInfo>,
185
inherited_variables: &HashSet<Identifier>,
···
65
let mut locals = VariableMap::new();
66
let mut store = LazyStore::new();
67
let mut scoped_store = LazyScopedVariables::new();
68
+
let mut lazy_graph = LazyGraph::new();
69
let mut function_parameters = Vec::new();
70
let mut prev_element_debug_info = HashMap::new();
71
···
99
prev_element_debug_info: &mut prev_element_debug_info,
100
cancellation_flag,
101
};
102
+
lazy_graph.evaluate(&mut exec)?;
103
// make sure any unforced values are now forced, to surface any problems
104
// hidden by the fact that the values were unused
105
store.evaluate_all(&mut exec)?;
···
138
mat: &'a QueryMatch<'a, 'tree>,
139
store: &'a mut LazyStore,
140
scoped_store: &'a mut LazyScopedVariables,
141
+
lazy_graph: &'a mut LazyGraph,
142
function_parameters: &'a mut Vec<graph::Value>, // re-usable buffer to reduce memory allocations
143
prev_element_debug_info: &'a mut HashMap<GraphElementKey, DebugInfo>,
144
error_context: StatementContext,
···
177
locals: &mut VariableMap<'l, LazyValue>,
178
store: &mut LazyStore,
179
scoped_store: &mut LazyScopedVariables,
180
+
lazy_graph: &mut LazyGraph,
181
function_parameters: &mut Vec<graph::Value>,
182
prev_element_debug_info: &mut HashMap<GraphElementKey, DebugInfo>,
183
inherited_variables: &HashSet<Identifier>,
+97
-33
src/execution/lazy/statements.rs
+97
-33
src/execution/lazy/statements.rs
···
22
use super::EvaluationContext;
23
use super::GraphElementKey;
24
25
/// Lazy graph statements
26
#[derive(Debug)]
27
pub(super) enum LazyStatement {
···
112
}
113
114
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
115
-
let node = self.node.evaluate_as_graph_node(exec)?;
116
for attribute in &self.attributes {
117
let value = attribute.value.evaluate(exec)?;
118
let prev_debug_info = exec.prev_element_debug_info.insert(
119
GraphElementKey::NodeAttribute(node, attribute.name.clone()),
120
self.debug_info.clone(),
121
);
122
-
exec.graph[node]
123
.attributes
124
.add(attribute.name.clone(), value)
125
-
.map_err(|_| {
126
-
ExecutionError::DuplicateAttribute(format!(
127
-
"{} on {} at {} and {}",
128
-
attribute.name,
129
-
node,
130
-
prev_debug_info.unwrap(),
131
-
self.debug_info,
132
-
))
133
-
})?;
134
}
135
Ok(())
136
}
···
171
}
172
173
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
174
-
let source = self.source.evaluate_as_graph_node(exec)?;
175
-
let sink = self.sink.evaluate_as_graph_node(exec)?;
176
let prev_debug_info = exec
177
.prev_element_debug_info
178
.insert(GraphElementKey::Edge(source, sink), self.debug_info.clone());
···
180
Ok(edge) => edge,
181
Err(_) => {
182
return Err(ExecutionError::DuplicateEdge(format!(
183
-
"({} -> {}) at {} and {}",
184
-
source,
185
-
sink,
186
-
prev_debug_info.unwrap(),
187
-
self.debug_info,
188
-
)))?
189
}
190
};
191
edge.attributes = self.attributes.clone();
···
228
}
229
230
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
231
-
let source = self.source.evaluate_as_graph_node(exec)?;
232
-
let sink = self.sink.evaluate_as_graph_node(exec)?;
233
for attribute in &self.attributes {
234
let value = attribute.value.evaluate(exec)?;
235
let edge = match exec.graph[source].get_edge_mut(sink) {
···
243
GraphElementKey::EdgeAttribute(source, sink, attribute.name.clone()),
244
self.debug_info.clone(),
245
);
246
-
edge.attributes
247
-
.add(attribute.name.clone(), value)
248
-
.map_err(|_| {
249
-
ExecutionError::DuplicateAttribute(format!(
250
-
"{} on edge ({} -> {}) at {} and {}",
251
-
attribute.name,
252
-
source,
253
-
sink,
254
-
prev_debug_info.unwrap(),
255
-
self.debug_info,
256
-
))
257
-
})?;
258
}
259
Ok(())
260
}
···
22
use super::EvaluationContext;
23
use super::GraphElementKey;
24
25
+
/// Lazy graph
26
+
#[derive(Debug)]
27
+
pub(super) struct LazyGraph {
28
+
edge_statements: Vec<LazyStatement>,
29
+
attr_statements: Vec<LazyStatement>,
30
+
print_statements: Vec<LazyStatement>,
31
+
}
32
+
33
+
impl LazyGraph {
34
+
pub(super) fn new() -> Self {
35
+
LazyGraph {
36
+
edge_statements: Vec::new(),
37
+
attr_statements: Vec::new(),
38
+
print_statements: Vec::new(),
39
+
}
40
+
}
41
+
42
+
pub(super) fn push(&mut self, stmt: LazyStatement) {
43
+
match stmt {
44
+
LazyStatement::AddGraphNodeAttribute(_) => self.attr_statements.push(stmt),
45
+
LazyStatement::CreateEdge(_) => self.edge_statements.push(stmt),
46
+
LazyStatement::AddEdgeAttribute(_) => self.attr_statements.push(stmt),
47
+
LazyStatement::Print(_) => self.print_statements.push(stmt),
48
+
}
49
+
}
50
+
51
+
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
52
+
for stmt in &self.edge_statements {
53
+
stmt.evaluate(exec)?;
54
+
}
55
+
for stmt in &self.attr_statements {
56
+
stmt.evaluate(exec)?;
57
+
}
58
+
for stmt in &self.print_statements {
59
+
stmt.evaluate(exec)?;
60
+
}
61
+
Ok(())
62
+
}
63
+
}
64
+
65
/// Lazy graph statements
66
#[derive(Debug)]
67
pub(super) enum LazyStatement {
···
152
}
153
154
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
155
+
let node = self
156
+
.node
157
+
.evaluate_as_graph_node(exec)
158
+
.with_context(|| "Evaluating target node".to_string().into())?;
159
for attribute in &self.attributes {
160
let value = attribute.value.evaluate(exec)?;
161
let prev_debug_info = exec.prev_element_debug_info.insert(
162
GraphElementKey::NodeAttribute(node, attribute.name.clone()),
163
self.debug_info.clone(),
164
);
165
+
if let Err(_) = exec.graph[node]
166
.attributes
167
.add(attribute.name.clone(), value)
168
+
{
169
+
return Err(ExecutionError::DuplicateAttribute(format!(
170
+
"{} on {}",
171
+
attribute.name, node,
172
+
)))
173
+
.with_context(|| {
174
+
(
175
+
prev_debug_info.unwrap().into(),
176
+
self.debug_info.clone().into(),
177
+
)
178
+
.into()
179
+
});
180
+
};
181
}
182
Ok(())
183
}
···
218
}
219
220
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
221
+
let source = self
222
+
.source
223
+
.evaluate_as_graph_node(exec)
224
+
.with_context(|| "Evaluating edge source".to_string().into())?;
225
+
let sink = self
226
+
.sink
227
+
.evaluate_as_graph_node(exec)
228
+
.with_context(|| "Evaluating edge sink".to_string().into())?;
229
let prev_debug_info = exec
230
.prev_element_debug_info
231
.insert(GraphElementKey::Edge(source, sink), self.debug_info.clone());
···
233
Ok(edge) => edge,
234
Err(_) => {
235
return Err(ExecutionError::DuplicateEdge(format!(
236
+
"({} -> {})",
237
+
source, sink,
238
+
)))
239
+
.with_context(|| {
240
+
(
241
+
prev_debug_info.unwrap().into(),
242
+
self.debug_info.clone().into(),
243
+
)
244
+
.into()
245
+
});
246
}
247
};
248
edge.attributes = self.attributes.clone();
···
285
}
286
287
pub(super) fn evaluate(&self, exec: &mut EvaluationContext) -> Result<(), ExecutionError> {
288
+
let source = self
289
+
.source
290
+
.evaluate_as_graph_node(exec)
291
+
.with_context(|| "Evaluating edge source".to_string().into())?;
292
+
let sink = self
293
+
.sink
294
+
.evaluate_as_graph_node(exec)
295
+
.with_context(|| "Evaluating edge sink".to_string().into())?;
296
for attribute in &self.attributes {
297
let value = attribute.value.evaluate(exec)?;
298
let edge = match exec.graph[source].get_edge_mut(sink) {
···
306
GraphElementKey::EdgeAttribute(source, sink, attribute.name.clone()),
307
self.debug_info.clone(),
308
);
309
+
if let Err(_) = edge.attributes.add(attribute.name.clone(), value) {
310
+
return Err(ExecutionError::DuplicateAttribute(format!(
311
+
"{} on edge ({} -> {})",
312
+
attribute.name, source, sink,
313
+
)))
314
+
.with_context(|| {
315
+
(
316
+
prev_debug_info.unwrap().into(),
317
+
self.debug_info.clone().into(),
318
+
)
319
+
.into()
320
+
});
321
+
}
322
}
323
Ok(())
324
}
+6
-1
src/execution/lazy/values.rs
+6
-1
src/execution/lazy/values.rs
···
13
use std::fmt;
14
15
use crate::execution::error::ExecutionError;
16
use crate::graph::GraphNodeRef;
17
use crate::graph::SyntaxNodeRef;
18
use crate::graph::Value;
···
184
}
185
186
fn resolve<'a>(&self, exec: &'a mut EvaluationContext) -> Result<LazyValue, ExecutionError> {
187
-
let scope = self.scope.as_ref().evaluate_as_syntax_node(exec)?;
188
let scoped_store = &exec.scoped_store;
189
scoped_store.evaluate(&scope, &self.name, exec)
190
}
···
13
use std::fmt;
14
15
use crate::execution::error::ExecutionError;
16
+
use crate::execution::error::ResultWithExecutionError;
17
use crate::graph::GraphNodeRef;
18
use crate::graph::SyntaxNodeRef;
19
use crate::graph::Value;
···
185
}
186
187
fn resolve<'a>(&self, exec: &'a mut EvaluationContext) -> Result<LazyValue, ExecutionError> {
188
+
let scope = self
189
+
.scope
190
+
.as_ref()
191
+
.evaluate_as_syntax_node(exec)
192
+
.with_context(|| format!("Evaluating scope of variable _.{}", self.name).into())?;
193
let scoped_store = &exec.scoped_store;
194
scoped_store.evaluate(&scope, &self.name, exec)
195
}
+3
-3
tests/it/lazy_execution.rs
+3
-3
tests/it/lazy_execution.rs