implement mutation of the current element (_THIS_)
while implementing this, I've discovered a conceptual error: we allow to accept attributes, even when we've already entered the child scope. This means that we can not predictable get back at the "last" (i.e. the currently touched) element, because this might be such an attribute. So a really correct implementation would have to memorise the "current" element, which is really tricky, given the various ways of touching elements in our diff language. In the end I've decided to ignore this problem (maybe a better solution would have been to disallow those "late" attributes?) My reasoning is that attributes are unlikely to be full records, rather just values, and values are never mutated. (but note that it is definitively possible to have an record as attribute!)
This commit is contained in:
parent
daa13ab6dc
commit
289bc7114c
3 changed files with 36 additions and 3 deletions
|
|
@ -474,6 +474,25 @@ namespace diff{
|
|||
alteredContent.resetPos();
|
||||
}
|
||||
|
||||
/** get the tail element.
|
||||
* @return either the last child, or the last attribute, when children are empty.
|
||||
* @note typically this might be used to get back at the element "just added",
|
||||
* as when muting a child node in diff application. But there is a loophole:
|
||||
* we might have added an attribute even when there are already children.
|
||||
*/
|
||||
VAL const&
|
||||
accessLast()
|
||||
{
|
||||
if (record_.empty())
|
||||
throw error::State("Record is empty, unable to access (last) element.");
|
||||
|
||||
if (record_.children_.empty())
|
||||
return record_.attribs_.back();
|
||||
else
|
||||
return record_.children_.back();
|
||||
}
|
||||
|
||||
|
||||
/* === extension point for building specific value types === */
|
||||
/*
|
||||
* the following builder functions need to be specialised
|
||||
|
|
|
|||
|
|
@ -204,6 +204,20 @@ namespace diff{
|
|||
GenNode const&
|
||||
find_child (GenNode::ID const& idi)
|
||||
{
|
||||
if (alteredRec().empty())
|
||||
throw error::State(_Fmt("Attempt to mutate element %s, but current target data scope is empty. "
|
||||
"Sender and receiver out of sync?") % idi.getSym()
|
||||
, LUMIERA_ERROR_DIFF_CONFLICT);
|
||||
|
||||
// Short-cut-mutation: look at the last element.
|
||||
// this should be the one just added. BUT NOTE: this fails
|
||||
// when adding an attribute after entering the child scope.
|
||||
// Since attributes are typically values and not mutated,
|
||||
// this inaccuracy was deemed acceptable
|
||||
auto& current = out().accessLast();
|
||||
if (Ref::THIS.matches(idi) or current.matches(idi))
|
||||
return current;
|
||||
|
||||
for (auto & child : alteredRec())
|
||||
if (child.idi == idi)
|
||||
return child;
|
||||
|
|
@ -217,7 +231,7 @@ namespace diff{
|
|||
move_into_new_sequence (Iter pos)
|
||||
{
|
||||
if (src().currIsAttrib())
|
||||
out().appendAttrib (move(*pos));
|
||||
out().appendAttrib (move(*pos)); //////////////TICKET #969 was it a good idea to allow adding attributes "after the fact"?
|
||||
else
|
||||
out().appendChild (move(*pos));
|
||||
}
|
||||
|
|
@ -233,7 +247,7 @@ namespace diff{
|
|||
if (n.isTypeID())
|
||||
out().setType (n.data.get<string>());
|
||||
else
|
||||
out().appendAttrib(n);
|
||||
out().appendAttrib(n); //////////////TICKET #969 dto.
|
||||
else
|
||||
{
|
||||
out().appendChild(n);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ namespace test{
|
|||
, skip(CHILD_T)
|
||||
, del(CHILD_T)
|
||||
, pick(Ref::CHILD) // pick a child anonymously
|
||||
, mut(Ref::THIS)
|
||||
, mut(Ref::THIS) // mutate the current element (the one just picked)
|
||||
, ins(ATTRIB3)
|
||||
, ins(ATTRIB_NODE)
|
||||
, find(CHILD_A)
|
||||
|
|
|
|||
Loading…
Reference in a new issue