Skip to content

Commit

Permalink
feat(merge): Add check for when a parent removes a node that could ha…
Browse files Browse the repository at this point in the history
…ve been modified in another parent
  • Loading branch information
jpedroh committed Oct 27, 2023
1 parent d2ef14b commit 79b007a
Showing 1 changed file with 204 additions and 10 deletions.
214 changes: 204 additions & 10 deletions merge/src/odered_merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,28 @@ pub fn ordered_merge(
let has_matching_base_right = base_right_matchings
.find_matching_for(cur_right.unwrap())
.is_some();
let matching_left_right = left_right_matchings.get_matching_entry(
cur_left.unwrap().to_owned(),
cur_right.unwrap().to_owned(),
let has_bidirectional_matching_left_right = left_right_matchings
.get_matching_entry(
cur_left.unwrap().to_owned(),
cur_right.unwrap().to_owned(),
);
let left_has_matching_in_right =
left_right_matchings.find_matching_for(cur_left.unwrap());
let right_has_matching_in_left =
left_right_matchings.find_matching_for(cur_right.unwrap());

println!(
"{} {} {} {}",
left_has_matching_in_right.is_none(),
has_matching_base_left,
right_has_matching_in_left.is_some(),
has_matching_base_right
);

// The nodes are unchanged
if has_matching_base_left
&& has_matching_base_right
&& matching_left_right.is_some()
&& matching_left_right.unwrap().is_perfect_match
&& has_bidirectional_matching_left_right.is_some()
{
result_children.push(ordered_merge(
&cur_left.unwrap(),
Expand All @@ -98,8 +110,7 @@ pub fn ordered_merge(
// This is the case where left and right both add the same nodes
else if !has_matching_base_left
&& !has_matching_base_right
&& matching_left_right.is_some()
&& matching_left_right.unwrap().is_perfect_match
&& has_bidirectional_matching_left_right.is_some()
{
result_children.push(ordered_merge(
&cur_left.unwrap(),
Expand All @@ -113,7 +124,7 @@ pub fn ordered_merge(
cur_left = children_left_it.next();
cur_right = children_right_it.next();
} else if !has_matching_base_left
&& matching_left_right.is_none()
&& has_bidirectional_matching_left_right.is_none()
&& has_matching_base_right
{
result_children.push(cur_left.unwrap().to_owned());
Expand All @@ -132,7 +143,7 @@ pub fn ordered_merge(
cur_left = children_left_it.next();
cur_right = children_right_it.next();
} else if !has_matching_base_right
&& matching_left_right.is_none()
&& has_bidirectional_matching_left_right.is_none()
&& has_matching_base_left
{
result_children.push(cur_right.unwrap().to_owned());
Expand All @@ -152,14 +163,48 @@ pub fn ordered_merge(
cur_right = children_right_it.next();
} else if !has_matching_base_left
&& !has_matching_base_right
&& matching_left_right.is_none()
&& has_bidirectional_matching_left_right.is_none()
{
result_children.push(CSTNode::Conflict {
left: Box::new(Some(cur_left.unwrap().to_owned())),
right: Box::new(Some(cur_right.unwrap().to_owned())),
});

cur_left = children_left_it.next();
cur_right = children_right_it.next();
} else if left_has_matching_in_right.is_none()
&& has_matching_base_left
&& right_has_matching_in_left.is_some()
&& has_matching_base_right
{
if !base_left_matchings
.find_matching_for(cur_left.unwrap())
.unwrap()
.is_perfect_match
{
result_children.push(CSTNode::Conflict {
left: Box::new(Some(cur_left.unwrap().to_owned())),
right: Box::new(None),
});
}

cur_left = children_left_it.next();
} else if left_has_matching_in_right.is_some()
&& has_matching_base_left
&& right_has_matching_in_left.is_none()
&& has_matching_base_right
{
if !base_right_matchings
.find_matching_for(cur_right.unwrap())
.unwrap()
.is_perfect_match
{
result_children.push(CSTNode::Conflict {
left: Box::new(None),
right: Box::new(Some(cur_right.unwrap().to_owned())),
});
}

cur_right = children_right_it.next();
}
}
Expand Down Expand Up @@ -688,4 +733,153 @@ mod tests {
},
)
}

#[test]
fn it_merges_when_one_parent_removes_a_node_that_was_not_changed_in_another_parent() {
let base = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
CSTNode::Terminal {
kind: "kind_b".into(),
value: "value_b".into(),
},
],
};

let left = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
CSTNode::Terminal {
kind: "kind_b".into(),
value: "value_b".into(),
},
],
};

let right = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![CSTNode::Terminal {
kind: "kind_b".into(),
value: "value_b".into(),
}],
};

assert_merge_output_is(
base,
left,
right,
CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![CSTNode::Terminal {
kind: "kind_b".into(),
value: "value_b".into(),
}],
},
)
}

#[test]
fn it_detects_a_conflit_when_one_parent_removes_a_node_that_was_changed_in_another_parent() {
let base = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::NonTerminal {
kind: "subtree".into(),
children: vec![CSTNode::Terminal {
kind: "kind_b".into(),
value: "value_b".into(),
}],
},
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
],
};

let left = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::NonTerminal {
kind: "subtree".into(),
children: vec![CSTNode::Terminal {
kind: "kind_c".into(),
value: "value_c".into(),
}],
},
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
],
};

let right = CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
}],
};

assert_merge_output_is(
base.clone(),
left.clone(),
right.clone(),
CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::Conflict {
left: Some(CSTNode::NonTerminal {
kind: "subtree".into(),
children: vec![CSTNode::Terminal {
kind: "kind_c".into(),
value: "value_c".into(),
}],
})
.into(),
right: None.into(),
},
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
],
},
);

assert_merge_output_is(
base,
right,
left,
CSTNode::NonTerminal {
kind: "kind".into(),
children: vec![
CSTNode::Conflict {
left: None.into(),
right: Some(CSTNode::NonTerminal {
kind: "subtree".into(),
children: vec![CSTNode::Terminal {
kind: "kind_c".into(),
value: "value_c".into(),
}],
})
.into(),
},
CSTNode::Terminal {
kind: "kind_a".into(),
value: "value_a".into(),
},
],
},
)
}
}

0 comments on commit 79b007a

Please sign in to comment.