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
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-07-28 01:17:50 +02:00
|
|
|
TreeDiffMutatorBinding::injectNew (GenNode const& n)
|
2016-07-25 15:21:30 +02:00
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("inject a new element at current abstract 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
|
|
|
{
|
|
|
|
|
injectNew (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
|
TODO("(re)initialise the diff application machinery");
|
2016-07-24 15:16:06 +02:00
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
REQUIRE (1 == scopes_.size());
|
|
|
|
|
scopes_.top().init();
|
2016-07-24 15:16:06 +02:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-07-25 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-07-24 15:16:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::diff
|