Skip to content

Commit 66032b4

Browse files
committed
Use transcation with for loops
1 parent 4e897de commit 66032b4

File tree

5 files changed

+62
-86
lines changed

5 files changed

+62
-86
lines changed

src/ps/forward.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ impl<'a> RuleMut<'a> for Forward {
7272
| "command_name_expr"
7373
| "expression_with_unary_operator"
7474
| "while_condition"
75+
| "for_condition"
7576
| "member_name" => {
7677
if view.child_count() == 1 {
7778
if let Some(child_data) = view.child(0).ok_or(Error::invalid_child())?.data() {

src/ps/loops.rs

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{
22
ps::{
3-
comparison::infer_comparison,
43
LoopStatus::{Dead, Inifite, OneTurn},
54
Powershell::{self, Loop, Raw},
65
Value::{self, Bool},
@@ -33,15 +32,19 @@ impl IteratorVariable {
3332
/// use minusone::ps::build_powershell_tree;
3433
/// use minusone::ps::linter::Linter;
3534
/// use minusone::ps::forward::Forward;
35+
/// use minusone::ps::bool::Comparison;
3636
/// use minusone::ps::integer::ParseInt;
3737
/// use minusone::ps::integer::AddInt;
38+
/// use minusone::ps::var::Var;
3839
/// use minusone::ps::loops::ForStatementCondition;
3940
///
4041
/// let mut tree = build_powershell_tree("for ($i = 132 + 324 - 3; $i -lt 200 - 190; $i++) {echo $i}").unwrap();
4142
/// tree.apply_mut(&mut (
4243
/// ParseInt::default(),
4344
/// AddInt::default(),
45+
/// Comparison::default(),
4446
/// Forward::default(),
47+
/// Var::default(),
4548
/// ForStatementCondition::default(),
4649
/// )).unwrap();
4750
///
@@ -71,48 +74,7 @@ impl<'a> RuleMut<'a> for ForStatementCondition {
7174
) -> crate::error::MinusOneResult<()> {
7275
let view = node.view();
7376
match view.kind() {
74-
"for_statement" => {
75-
if let (Some(initialisation), Some(comparison)) = (
76-
view.named_child("for_initializer")
77-
.map(|n| n.smallest_child()),
78-
view.named_child("for_condition")
79-
.map(|n| n.smallest_child()),
80-
) {
81-
if comparison.kind() == "comparison_expression"
82-
&& initialisation.kind() == "assignment_expression"
83-
{
84-
if let (
85-
Some(var_name),
86-
Some(value),
87-
Some(comp_left),
88-
Some(operator),
89-
Some(comp_right),
90-
) = (
91-
initialisation
92-
.child(0)
93-
.and_then(|n| Some(n.text().ok()?.to_lowercase())),
94-
initialisation.child(2),
95-
comparison.child(0),
96-
comparison.child(1),
97-
comparison.child(2),
98-
) {
99-
if let Some(false) =
100-
infer_comparison(&comp_left, &operator, &comp_right)
101-
.or((comp_left.text().unwrap_or_default().to_lowercase()
102-
== var_name)
103-
.then_some(1)
104-
.and(infer_comparison(&value, &operator, &comp_right)))
105-
.or((comp_right.text().unwrap_or_default() == var_name)
106-
.then_some(1)
107-
.and(infer_comparison(&comp_left, &operator, &value)))
108-
{
109-
node.set(Loop(Dead));
110-
}
111-
}
112-
}
113-
}
114-
}
115-
"while_condition" => {
77+
"while_condition" | "for_condition" => {
11678
if let Some(&Raw(Bool(false))) = view.data() {
11779
node.set_by_node_id(view.parent().unwrap().id(), Loop(Dead));
11880
node.apply_transaction();
@@ -255,10 +217,12 @@ impl<'a> RuleMut<'a> for ForStatementFlowControl {
255217

256218
#[cfg(test)]
257219
mod test {
220+
use crate::ps::bool::Comparison;
258221
use crate::ps::build_powershell_tree;
259222
use crate::ps::forward::Forward;
260223
use crate::ps::integer::ParseInt;
261224
use crate::ps::loops::{ForStatementCondition, ForStatementFlowControl};
225+
use crate::ps::var::Var;
262226
use crate::ps::LoopStatus::{Dead, OneTurn};
263227
use crate::ps::Powershell::{Loop, Raw};
264228
use crate::ps::Value::Num;
@@ -267,8 +231,10 @@ mod test {
267231
fn test_dead_for_statement() {
268232
let mut tree = build_powershell_tree("for ($i = 0; $i -gt 1; $i++) {}").unwrap();
269233
tree.apply_mut(&mut (
270-
ParseInt::default(),
271234
Forward::default(),
235+
ParseInt::default(),
236+
Comparison::default(),
237+
Var::default(),
272238
ForStatementCondition::default(),
273239
))
274240
.unwrap();

src/ps/strategy.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,12 @@ impl Strategy<Powershell> for PowershellStrategy {
1515
"statement_block" => {
1616
let parent = node.parent().unwrap();
1717
match parent.kind() {
18-
"while_statement" => {
19-
// Don't visit node inferred node with a branch set to false
20-
if let Some(condition) = parent.named_child("condition") {
21-
if let Some(Raw(Bool(false))) = condition.data() {
22-
return Ok(Break);
23-
}
24-
}
25-
// Any other inferred type led to unpredictable branch visit
26-
Ok(Continue(Unpredictable))
27-
}
28-
"for_statement" => {
29-
if let Some(Powershell::Loop(LoopStatus::Dead)) = parent.data() {
30-
return Ok(Break);
31-
}
18+
"for_statement" | "while_statement" => match parent.data() {
19+
Some(Powershell::Loop(LoopStatus::Dead)) => Ok(Break),
20+
Some(Powershell::Loop(LoopStatus::OneTurn)) => Ok(Continue(Predictable)),
21+
_ => Ok(Continue(Unpredictable)),
22+
},
3223

33-
Ok(Continue(Unpredictable))
34-
}
3524
"if_statement" => {
3625
// if ($true) control flow
3726
if let Some(condition) = parent.named_child("condition") {
@@ -119,6 +108,8 @@ impl Strategy<Powershell> for PowershellStrategy {
119108
// We were not able to infer type so we are in an unpredictable case
120109
Ok(Continue(Unpredictable))
121110
}
111+
// Do not visit for iterator, as it is unsure if and when they are executed
112+
"for_iterator" => Ok(Break),
122113
// All this statement are labeled and not inferred at this moment
123114
"trap_statement" | "try_statement" | "catch_clause" | "finally_clause"
124115
| "data_statement" | "parallel_statement" | "sequence_statement"

src/ps/var.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ impl<'a> RuleMut<'a> for Var {
236236
}
237237
}
238238

239-
"while_statement" => {
239+
"while_statement" | "for_statement" => {
240240
node.start_transaction()?;
241241
}
242242

@@ -281,21 +281,14 @@ impl<'a> RuleMut<'a> for Var {
281281
if let (current_value, Some(new_value)) =
282282
(scope.get_var(&var_name), right.data())
283283
{
284-
// disable anything from for_initializer
285-
if view.get_parent_of_types(vec!["for_initializer"]).is_some() {
286-
scope.forget(&var_name);
287-
} else {
288-
// only predictable assignment is handled of local var
289-
let is_local = scope.is_local(&var_name).unwrap_or(true);
290-
if flow == ControlFlow::Continue(BranchFlow::Predictable)
291-
|| is_local
292-
{
293-
match assign_handler(current_value, operator, new_value) {
294-
Some(assign_value) => {
295-
scope.assign(&var_name, assign_value)
296-
}
297-
_ => scope.forget(&var_name),
298-
}
284+
// only predictable assignment is handled of local var
285+
let is_local = scope.is_local(&var_name).unwrap_or(true);
286+
if flow == ControlFlow::Continue(BranchFlow::Predictable)
287+
|| is_local
288+
{
289+
match assign_handler(current_value, operator, new_value) {
290+
Some(assign_value) => scope.assign(&var_name, assign_value),
291+
_ => scope.forget(&var_name),
299292
}
300293
}
301294
}

src/tree.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,6 @@ impl<T> Storage for HashMapStorage<T> {
201201
Ok(())
202202
}
203203

204-
/// use to monitor if the storage was updated
205-
/// between the start and the end function
206-
///
207204
/// # Example
208205
/// ```
209206
/// extern crate tree_sitter;
@@ -226,12 +223,6 @@ impl<T> Storage for HashMapStorage<T> {
226223
/// assert_eq!(storage.get(root_id), Some(&42));
227224
/// storage.apply_transaction();
228225
/// assert_eq!(storage.get(root_id), Some(&42));
229-
///
230-
/// storage.start_transaction();
231-
/// storage.set(root_id, 0);
232-
/// assert_eq!(storage.get(root_id), Some(&0));
233-
/// storage.abort_transaction();
234-
/// assert_eq!(storage.get(root_id), Some(&42));
235226
/// ```
236227
fn apply_transaction(&mut self) {
237228
let node_ids: Vec<usize> = self.pending.keys().cloned().collect();
@@ -244,8 +235,42 @@ impl<T> Storage for HashMapStorage<T> {
244235
});
245236
self.is_ongoing_transaction = false;
246237
}
238+
239+
/// Abort transaction by forget all the variables to update
240+
///
241+
/// # Example
242+
/// ```
243+
/// extern crate tree_sitter;
244+
/// extern crate tree_sitter_powershell;
245+
/// use tree_sitter::{Parser, Language};
246+
/// use tree_sitter_powershell::LANGUAGE as powershell_language;
247+
/// use minusone::tree::{Storage, HashMapStorage};
248+
///
249+
/// let mut parser = Parser::new();
250+
/// parser.set_language(&powershell_language.into()).unwrap();
251+
///
252+
/// let ts_tree = parser.parse("4+5", None).unwrap();
253+
/// let mut storage = HashMapStorage::<u32>::default();
254+
/// let root_id = ts_tree.root_node().id();
255+
///
256+
/// storage.set(root_id, 42);
257+
/// storage.start_transaction();
258+
///
259+
/// storage.start_transaction();
260+
/// storage.set(root_id, 0);
261+
/// assert_eq!(storage.get(root_id), Some(&0));
262+
/// storage.abort_transaction();
263+
/// assert_eq!(storage.get(root_id), None);
264+
/// ```
247265
fn abort_transaction(&mut self) {
248-
self.pending.clear();
266+
let keys: Vec<usize> = self.pending.keys().cloned().collect();
267+
let keys_to_forget: Vec<usize> = keys
268+
.iter()
269+
.filter(|k| matches!(self.pending.remove(k), Some(PendingAction::Add(_))))
270+
.cloned()
271+
.collect();
272+
keys_to_forget.iter().for_each(|k| _ = self.map.remove(k));
273+
249274
self.is_ongoing_transaction = false;
250275
}
251276
}

0 commit comments

Comments
 (0)