CCA Wiki
CCA Software Resources
Menu [hide]

On splicing in bocca

Splicing in bocca
print PDF
The short version

  • Bocca will only rewrite in impls the bocca protected blocks.
  • Bocca will only generate non-protected code at component create.
  • Bocca will *always* rewrite the bocca protected blocks (not sometimes) unless told not to.
  • When more than one bocca block goes into a single babel block at generation, each must have clear prefix or suffix position in the splicer block and the tag is the tag on the block + :prolog or :epilog.
  • No bocca code goes in _misc.
  • No unconditional bocca native code goes in _include unless it is to include language standard headers. corollary: boccaSetServices and boccaForceUsePortInclude must appear in sidl.
  • Bocca macro code is allowed in _include; the BOCCA_ prefix is always used.
  • If the user deletes a bocca protected block entirely, it will not be reinserted-- the user gets what they deserve. If they want it back, they can insert the empty delimiters and then have bocca update all protected blocks by adding and removing a dummy port.

The long version

Bocca understands babel splicer blocks and leverages those conventions as much as possible to manage bocca-generated code inside those blocks while never stepping on user-written code. This note is primarily for the users to understand the lengths we go to to preserve their code and for the developers to gain a common understanding of how splicing is handled in the bocca implementation.

Background
  • Babel blocks are delimited DO-NOT-DELETE splicer.begin/end(tag).
  • Bocca generated blocks are delimited bocca.protected.begin/end(tag).
  • User-written blocks in bocca-generated files (only sidl currently) are delimited DO-NOT-DELETE bocca.splicer.begin/end(tag).

To generalize the above delimiters, they consist of a tag in parentheses and a leading key string that is always followed by .begin(tag) or .end(tag). The key string examples here would be "DO-NOT-DELETE splicer", "bocca.protected", and "DO-NOT-DELETE bocca.splicer". Delimited block tags are always well-nested; ill-nested blocks cause splicers to generate errors and cancel any overwrites that would occur in a successful splicing.
Summary: KEY.begin(TAG)/KEY.end(TAG) is the delimiter pair.

Handling SIDL

  • Bocca generates SIDL package/class/interface/CCA Port declarations but leaves the methods within them to the user to write. The user puts their interface code in a bocca.splicer block.
  • Bocca generates a SIDL CCA component declaration leaving a user block in the sidl but also including some bocca-related methods outside the user block.

Handling Impl files

Bocca must handle a component's impl files when a component is created and any time the bocca-information is changed, such as when a new CCA port is added to update the bocca-generated methods.

Most of the Babel splicer blocks in a Component implementation file are application-related methods that only the component writer knows how to implement. Bocca does not touch these methods at all. Bocca can (and normally does) generate default implementations for methods of the CCA interfaces gov.cca.Component, gov.cca.ComponentRelease, gov.cca.ports.GoPort (at the user's request) and portions of the component's private data. Bocca does not claim ownership of any method normally required by babel or cca specifications; bocca merely provides suggested implementations that the user may edit or discard.

Invoking the splicer to keep users happy

The bocca splicer is almost always be invoked with identical keys for source and target if replacement is intended and distinct keys if insertion is intended. In normal operations (generate a component, update a component for new ports) only the identical keys case is needed.
For initial definition of a method or methods, both keys are "DO-NOT-DELETE splicer"; for subsequent rewrite of the bocca-owned sections only, both keys are "bocca.protected".

When the tags match, the source block will be inserted (or appended if insertFirst=True is not passed).
To handle multiple bocca.protected in a single Babel splicer block, simply splice to the same target.

To handle multiple bocca tags inside a single bocca block, note that this requires no reference to a babel splicer key at all. Simply use extended bocca protected keys. In an example suited to setServices
targetKey="DO-NOT-DELETE bocca.protected", sourceKey="DO-NOT-DELETE bocca.protected.port"


In any operation in which any user code might be replaced, rejectSave=True should be passed and the .rej file generated should be put in the appropriate Trash directory and a warning issued about where old code can be found.
There are no such operations currently.

Algorithms

We distinguish for clarity (not because they are unique) several cases and explain what happens with splicing in each:

  • A new component is defined in bocca.
The sidl is generated.
From sidl the impl is generated with babel.
The bocca generates and inserts the setServices method default block and protected auxiliary function splices.
The generated auxiliaries contain bocca.protected keyed splices which the user should never edit.
The user can insert code in the cca standard-specified functions and their code will never be molested (1). If the user removes calls to the cca auxilary methods, they must provide alternative equivalent functionality.


  • An existing component is changed, e.g. a uses port is added.
The sidl file is regenerated, leaving user additions to the component inside the bocca.splicer block unchanged.
The bocca.protected blocks for the component are regenerated and replaced, given the new information.
If the user has manually deleted one of the bocca.protected blocks, it will not be reinserted unless the user inserts at least the needed delimiters.
If the user simply deletes the bocca.protected delimiters around a bocca code block, this has the effect of freezing that code in spite of any future changes bocca normally manages;
the generated code has been promoted to user code.


  • A bocca component is created based on an existing component implementation.
The user's sidl description of the component is copied into the bocca project.
The original sidl file (outside the bocca project) is never again referenced.
If there is also an impl file or files, they are:
used as the source for a second splicing after the initial bocca impl generation.
The default bocca code for setServices and go() is inserted unless suppressed by using
--import-impl-exact --exclude-impl-symbols=None.


Special cases of code changes outside bocca.protected splicers:

  • (1) An existing port instance is renamed (future feature)
All the CCA-related calls in the impl file which use the old port instance name
as a literal string (e.g. "myport") will be replaced with string literals of the
new port instance name. This is independent of where the literals are located.
Both user code and bocca-generated code will be updated with the new port name, but only in
the CCA functions handling port instance names.
If the port instance name is somehow computed instead of specified as a literal, manual
repairs may be needed when a port instance name is changed.


  • (2) Babel default exceptions
A babel default "not implemented exception" throw is always deleted when
the bocca splicer inserts code to an unimplemented setServices or other bocca-managed function.
Default exceptions are left in place by bocca in all other functions.


Splicing for power users
  • Users may want to splice or to extract splices from their own files. The splicer in bocca has a powerful python programming interface but is also accessible from the command line in the form of an extractor (bocca-extract) and splicer (bocca-merge). Either command responds to the --help switch with further information. There are many options to fine tune, replicating on the command line most of the functionality available in the programming interface.
  • Users are warned against any component maintenance model which uses both bocca and a collection of individual splice files to generate the final components to be compiled. Bocca is not designed for use in such models and sooner or later a splicing conflict will occur and will be fiendishly hard to debug.
  • The bocca-merge tool can be used independent of any bocca project to aid the renaming of a component implementation from one package and/or class name into another. Specifically it will migrate blocks from the old impl file into the new impl file generated from sidl where the names have been changed. Previously this kind of rename had to be done by hand or by custom written string substitution scripts.

Created by: baallan last modification: Friday 21 of September, 2007 [06:44:59 UTC] by baallan


Online users
6 online users