this is a subtle change in the semantics of the diff language,
actually IMHO a change towards the better. It was prompted by the
desire to integrate diff application onto GenNode-trees into the
implementation framework based on TreeMutator, and do away with
the dedicated implementation.
Now it is a matter of the *selector* to decide if a given layer
is responsible for "attributes". If so, then *all* elements within
this layer count as "attribute" and an after(Ref::ATTRIBS) verb
will fast forward behind *the end of this layer*
Note that the meta token Ref::ATTRIBS is a named GenNode,
and thus trivially responds to isNamed() == true
previously they where included in the middle of tree-mutator.hpp
This was straight forward, since the builder relies on the classes
defined in the detail headers.
However, the GenNode-binding needs to use a specifically configured
collection binding, and this in turn requires writing a recursive
lambda to deal with nested scopes. This gets us into trouble with
circular definition dependencies.
As a workaround we now only *declare* the DSL builder functions
in the tree-mutator-builder object, and additionally use auto on
all return types. This allows us to spell out the complete builder
definition, without mentioning any of the implementation classes.
Obviously, the detail headers have then to be included *after*
the builder definition, at bottom of tree-mutator.hpp
This also allows us to turn these implementation headers into
completely normal headers, with namespaces and transitive #includes
In the end, the whole setup looks much more "innocent" now.
But beware: the #include of the implementation headers at bottom
of tree-mutator.hpp needs to be given in reverse dependency order,
due to the circular inclusion (back to tree-mutator.hpp) in
conjunction with the inclusion guards!
- esp. verify the proper inclusion of the Selector closure in all Operations
- straighten the implementation of Attribute binding
- clean-up the error checking helpers
similar reordering for the third part.
This time most operations are either passed down anyway,
or are NOP, since attribute binding has no notion of 'order'
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.
...which mostly just is either ignoring the
operations or indicating failure on attempt to
'reorder' attributes (which don't have any notion of 'ordering')
overall, the structure of this implementation is still rather confusing,
yet any alternatives seem even less convincing
- if we want to avoid the delegation to base-class, we'd have
to duplicate several functions and the combined class would
handle two distinct concerns.
- any attempt to handle the IDs more "symmetrically" seems to
create additional problems on one side or the other
this also supersedes and removes the initial implementation
draft for attribute binding with the 'setAttribute' API
The elementary part of diff application incl. setting
new attribute values works by now.
The way we build this attribute binding, there is no single
entity to handle all attribute bindings. Thus the only way
to detect a missing binding is when none of the binding layers
was able to handle a given INS verb
since we're moving elements around to apply the diff,
dangerous situation might arise in case anyone takes a copy
of the mutator. Thus we effectively limit the possible
usage pattern and only allow to build an anonymous
TreeMutator subclass through the Builder-DSL.
The concrete "onion layers" of the TreeMutator are now limited
- to be created by the chaining operations of the Builder DSl
- to be moved into target location, retaining ownership.
the concern is for the structure of the builder to be
incomprehensible and completely buried within the
implementation details of the various binding layers