2016-07-24 15:16:06 +02:00
|
|
|
/*
|
|
|
|
|
TreeDiffMutatorBinding - implementation of diff application to opaque data
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2016, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @file tree-diff-mutator-binding.cpp
|
|
|
|
|
** Implementation of diff application to unspecific private data structures.
|
|
|
|
|
** This binding is the link between a generic interpreter for our
|
|
|
|
|
** »tree diff language« and a concrete TreeMutator implementation,
|
|
|
|
|
** as provided by the target data structure. We do not require much
|
|
|
|
|
** additional knowledge regarding the opaque target structure, beyond
|
|
|
|
|
** the ability to construct such a customised TreeMutator. For this reason,
|
|
|
|
|
** the implementation is mostly generic and thus can be emitted here within
|
|
|
|
|
** the library module -- with the exception of the ctor, which indeed picks
|
|
|
|
|
** up some specifics of the concrete usage situation and thus needs to be
|
|
|
|
|
** generated in usage context.
|
|
|
|
|
**
|
|
|
|
|
** @see tree-diff.cpp
|
|
|
|
|
** @see tree-diff-mutator-binding.cpp
|
|
|
|
|
** @see DiffVirtualisedApplication_test
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
#include "lib/diff/tree-diff-mutator-binding.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace diff{
|
|
|
|
|
|
2016-07-29 01:46:11 +02:00
|
|
|
ScopeManager::~ScopeManager() { }; ///< emit VTable here...
|
|
|
|
|
|
|
|
|
|
|
2016-07-24 15:16:06 +02:00
|
|
|
/* ======= Implementation of Tree Diff Application via TreeMutator ======= */
|
|
|
|
|
|
|
|
|
|
using util::unConst;
|
|
|
|
|
using util::cStr;
|
|
|
|
|
using util::_Fmt;
|
|
|
|
|
using std::move;
|
|
|
|
|
using std::swap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
|
|
|
|
|
using Mutator = Rec::Mutator;
|
|
|
|
|
using Content = Rec::ContentMutator;
|
|
|
|
|
using Iter = Content::Iter;
|
|
|
|
|
|
2016-07-24 15:16:06 +02:00
|
|
|
template<>
|
2016-07-28 01:17:50 +02:00
|
|
|
struct TreeDiffMutatorBinding::ScopeFrame
|
2016-07-24 15:16:06 +02:00
|
|
|
{
|
2016-07-25 15:21:30 +02:00
|
|
|
Mutator& target;
|
|
|
|
|
Content content;
|
|
|
|
|
|
|
|
|
|
ScopeFrame(Mutator& toModify)
|
|
|
|
|
: target(toModify)
|
|
|
|
|
, content()
|
|
|
|
|
{ }
|
2016-07-24 15:16:06 +02:00
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void init()
|
2016-07-24 15:16:06 +02:00
|
|
|
{
|
2016-07-25 15:21:30 +02:00
|
|
|
target.swapContent (content);
|
|
|
|
|
content.resetPos();
|
|
|
|
|
}
|
|
|
|
|
};
|
2016-07-24 15:16:06 +02:00
|
|
|
|
|
|
|
|
/** Storage: a stack of workspaces
|
|
|
|
|
* used to handle nested child objects */
|
|
|
|
|
std::stack<ScopeFrame> scopes_;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mutator& out() { return scopes_.top().target; }
|
|
|
|
|
Content& src() { return scopes_.top().content; }
|
|
|
|
|
Iter& srcPos() { return scopes_.top().content.pos; }
|
|
|
|
|
bool endOfData() { return srcPos() == src().end(); } /////TODO split into an actual scope end check and an non-null check
|
|
|
|
|
Rec& alteredRec() { return out(); }
|
|
|
|
|
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_in_target (GenNode const& elm, Literal oper)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (endOfData())
|
|
|
|
|
throw error::State(_Fmt("Unable to %s element %s from target as demanded; "
|
|
|
|
|
"no (further) elements in target sequence") % oper % elm
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
|
|
|
|
|
if (elm.matches(Ref::CHILD) and not srcPos()->isNamed())
|
|
|
|
|
return; // allow for anonymous pick or delete of children
|
|
|
|
|
|
|
|
|
|
if (not srcPos()->matches(elm))
|
|
|
|
|
throw error::State(_Fmt("Unable to %s element %s from target as demanded; "
|
|
|
|
|
"found element %s on current target position instead")
|
|
|
|
|
% oper % elm % *srcPos()
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (endOfData())
|
|
|
|
|
throw error::State(_Fmt("Premature end of target sequence, still expecting element %s; "
|
|
|
|
|
"unable to apply diff further.") % elm
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_found (GenNode const& elm, Iter const& targetPos)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (targetPos == src().end())
|
|
|
|
|
throw error::State(_Fmt("Premature end of sequence; unable to locate "
|
|
|
|
|
"element %s in the remainder of the target.") % elm
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_successful_location (GenNode const& elm)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (endOfData()
|
|
|
|
|
and not ( elm.matches(Ref::END) // after(_END_) -> its OK we hit the end
|
|
|
|
|
or (elm.matches(Ref::ATTRIBS) and src().children.empty()))) // after(_ATTRIBS_) -> if there are no children, it's OK to hit the end
|
|
|
|
|
throw error::State(_Fmt("Unable locate position 'after(%s)'") % elm.idi
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (scopes_.empty())
|
|
|
|
|
throw error::State(_Fmt("Unbalanced child scope bracketing tokens in diff; "
|
|
|
|
|
"When leaving scope %s, we fell out of root scope.") % idi.getSym()
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
|
|
|
|
|
if (alteredRec().empty())
|
|
|
|
|
throw error::State(_Fmt("Corrupted state. When leaving scope %s, "
|
|
|
|
|
"we found an empty parent scope.") % idi.getSym()
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (not endOfData())
|
|
|
|
|
throw error::State(_Fmt("Incomplete diff: when about to leave scope %s, "
|
|
|
|
|
"not all previously existing elements have been confirmed by the diff. "
|
|
|
|
|
"At least one spurious element %s was left over") % idi.getSym() % *srcPos()
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Iter
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::find_in_current_scope (GenNode const& elm)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
Iter end_of_scope = src().currIsAttrib()? src().attribs.end()
|
|
|
|
|
: src().children.end();
|
|
|
|
|
return std::find_if (srcPos()
|
|
|
|
|
,end_of_scope
|
|
|
|
|
,[&](auto& entry)
|
|
|
|
|
{
|
|
|
|
|
return entry.matches(elm);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GenNode const&
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::find_child (GenNode::ID const& idi)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
throw error::State(_Fmt("Attempt to mutate non existing child record; unable to locate child %s "
|
|
|
|
|
"after applying the diff. Current scope: %s") % idi.getSym() % alteredRec()
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::move_into_new_sequence (Iter pos)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (src().currIsAttrib())
|
|
|
|
|
out().appendAttrib (move(*pos)); //////////////TICKET #969 was it a good idea to allow adding attributes "after the fact"?
|
|
|
|
|
else
|
|
|
|
|
out().appendChild (move(*pos));
|
|
|
|
|
}
|
2016-07-24 15:16:06 +02:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
|
|
|
|
|
/* == Forwarding: error handling == */
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_in_target (GenNode const& elm, Literal oper)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__fail_not_found (GenNode const& elm)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-31 00:32:03 +02:00
|
|
|
void
|
|
|
|
|
TreeDiffMutatorBinding::__failMismatch (GenNode const& spec, Literal oper)
|
|
|
|
|
{
|
|
|
|
|
throw error::State(_Fmt("Unable to %s element %s. Current target binding "
|
|
|
|
|
"did not match as expected") % oper % spec
|
|
|
|
|
, LUMIERA_ERROR_DIFF_CONFLICT);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == Forwarding: mutation primitives == */
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::skipSrc()
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("skip next src element and advance abstract source position");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::matchSrc (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("ensure the next source element matches with given spec");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::acceptSrc (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("accept existing element, when matching the given spec");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::findSrc (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("locate designated element and accept it at current position");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::accept_until (GenNode const& refMark)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("repeatedly accept until encountering the mark");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::assignElm (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("locate already accepted element and assign given new payload");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::open_subScope (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("locate already accepted element and open recursive sub-scope for mutation");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::close_subScope()
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("finish and leave sub scope and return to invoking parent scope");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == Implementation of the list diff application primitives == */
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::ins (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
investigate and confirm the logic underlying the matchSrc, skipSrc and acceptSrc primitives
In Theory, acceptSrc and skipSrc are to operate symmetrically,
with the sole difference that skipSrc does not move anything
into the new content.
BUT, since skipSrc is also used to implement the `skip` verb,
which serves to discard garbage left back by a preceeding `find`,
we cannot touch the data found in the src position without risk
of SEGFAULT. For this reason, there is a dedicated matchSrc operation,
which shall be used to generate the verification step to properly
implement the `del` verb.
I've spent quite some time to verify the logic of predicate evaluation.
It seems to be OK: whenever the SELECTOR applies, then we'll perform
the local match, and then also we'll perform the skipSrc. Otherwise,
we'll delegate both operations likewise to the next lower layer,
without touching anything here.
2016-08-09 23:42:42 +02:00
|
|
|
bool success = treeMutator_->injectNew(n);
|
2016-07-31 00:32:03 +02:00
|
|
|
if (not success)
|
|
|
|
|
__failMismatch (n, "insert");
|
2016-07-25 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::del (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
__expect_in_target(n, "remove");
|
|
|
|
|
skipSrc();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::pick (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
__expect_in_target(n, "pick");
|
|
|
|
|
acceptSrc (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::skip (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
__expect_further_elements (n);
|
|
|
|
|
skipSrc();
|
|
|
|
|
} // assume the actual content has been moved away by a previous find()
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::find (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
__expect_further_elements (n);
|
|
|
|
|
// consume and leave waste, expected to be cleaned-up by skip() later
|
2016-07-28 01:17:50 +02:00
|
|
|
if (not this->findSrc(n));
|
2016-07-25 15:21:30 +02:00
|
|
|
__fail_not_found (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == Implementation of the tree diff application primitives == */
|
|
|
|
|
|
|
|
|
|
/** cue to a position behind the named node,
|
|
|
|
|
* thereby picking (accepting) all traversed elements
|
|
|
|
|
* into the reshaped new data structure as-is */
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::after (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
if (not accept_until(n))
|
|
|
|
|
__fail_not_found (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** assignment of changed value in one step */
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::set (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
assignElm (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** open nested scope to apply diff to child object */
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::mut (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
open_subScope (n);
|
|
|
|
|
|
2016-07-24 15:16:06 +02:00
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
Rec const& childRecord = child.data.get<Rec>();
|
|
|
|
|
TRACE (diff, "tree-diff: ENTER scope %s", cStr(childRecord));
|
2016-07-24 15:16:06 +02:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** finish and leave child object scope, return to parent */
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::emu (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
2016-07-24 15:16:06 +02:00
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
TRACE (diff, "tree-diff: LEAVE scope %s", cStr(describeScope()));
|
2016-07-24 15:16:06 +02:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
|
|
|
|
|
__expect_end_of_scope (n.idi);
|
|
|
|
|
close_subScope();
|
|
|
|
|
__expect_valid_parent_scope (n.idi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::initDiffApplication()
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
2016-07-30 18:23:45 +02:00
|
|
|
REQUIRE (scopeManger_);
|
|
|
|
|
REQUIRE (treeMutator_);
|
2016-07-25 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-07-24 15:16:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::diff
|