Jade internals
PrevJade internals 

Extending Jade

Utility classes

TODO: Explain Char, String, Vector, StringC, Ptr, Owner

TODO: Maybe move this to the "General overview".


Primitives are implemented as subclasses of PrimitiveObj (style/Insn.h, style/Insn.cxx). All primitives are defined in the files style/primitive.h and style/primitive.cxx. Adding a new primitive is done by adding a macro call of the form
PRIMITIVE(<class name prefix>,
	  "<primitive name>", 
          <req. args>, <opt. args>, <rest arg>)
to style/primitive.h and a macro call of the form
DEFPRIMITIVE(<class name prefix>, argc, argv,
	     context, interp, loc)
to style/primitive.cxx, followed by the body of the function PrimitiveObj::primitiveCall() as needed for the function you want to add.

For a new external procedure, use XPRIMITIVE instead of PRIMITIVE. The new procedure can be accessed using the public identifier

"UNREGISTERED::James Clark//Procedure::<primitive name>".

Example 3. The sin function

We can add the sin defined in clause of the DSSSL standard by appending
PRIMITIVE(Sin, "sin", 1, 0, 0)
to style/primitive.h and
DEFPRIMITIVE(Sin, argc, argv, context, interp, loc)
  double d;
  if (!argv[0]->realValue(d)) 
  return argError(interp, loc,
		    InterpreterMessages::notANumber, 0, argv[0]);
  return new (interp) RealObj(sin(d));
to style/primitive.cxx.

Expression language types

Relevant classes:


Adding a new expression language type is done by adding a new subclass of ELObj. Make sure to follow the advise in the section on garbage collection with respect to the size of the subclass.


You will have to add a method for generating objects of the new type. This will generally involve a line like
result = new (*interp_) <your class>(...)
The *interp_ argument to new is important to make the newly generated object properly garbage collected.

TODO: is this all ? add an example!


In order to create a completely new backend, you first need to create a new subclass of SerialFOTBuilder implementing the output format you are interested in. It is probably a good idea to take an existing backend as a skeleton.

TODO: More detail needed.

To make the new backend available to Jade, you have to add new values for your backend to JadeApp::OutputType and JadeApp::outputTypeNames and add a new case to the switch statement in JadeApp::makeFOTBuilder() returning an instance of your FOTBuilder subclass.

Flow objects

For a standard flow object, you must create a new subclass of FlowObj (atomic) or CompoundFlowObj (nonatomic). Do not forget to add a FLOW_OBJ macro call for the new class in the Interpreter::installFlowObjs() function in style/FlowObj.cxx.

The processInner() of the new class is responsible for calling the FOTBuilder function (or pair of functions for nonatomic flow objects) associated with the flow object in question. You may have to add these functions to the interface of the FOTBuilder class and provide default definitions there. These have to be overridden by the backends (FOTBuilder subclass) in order to implement the flow object in question.

TODO: explain extension flow objects

Command line switches

If you are adding a new Jade-specific option, add it to JadeApp. If the option you are adding influences the behaviour of the style engine, add it to DssslApp.

Adding an option amount to registering it in the constructor with registerOption() and handling it in processOption().

The CmdLineApp supports only single-letter options. You should make sure that you don't choose a letter that is already taken:

b, f, v

registered by CmdLineApp

c, C, D

registered by EntityApp

a, A, e, E, g, i, w

registered by ParserApp

G, 2, d, V

registered by DssslApp

t, o

registered by JadeApp

Example 4. A -s flag for DssslApp

Lets assume you have changed the StyleEngine constructor to accept one more bool parameter strict_, which you want to be set depending on the -s command line flag.

We add a new private member strict_ to DssslApp to hold the value until we pass it to the StyleEngine constructor. Thus we insert
bool strict_;	  
at the very end of the DssslApp class declaration in style/DssslApp.h.

Now we change the constructor to
DssslApp::DssslApp(int unitsPerInch)
: GroveApp("unicode"), unitsPerInch_(unitsPerInch),
  dssslSpecOption_(0), debugMode_(0), dsssl2_(0),
  strict_(0)  // this line is new
  registerOption('d', SP_T("dsssl_spec"));
  registerOption('V', SP_T("variable"));
  registerOption('s'); // this line is new
and the function processOption() to
void DssslApp::processOption(AppChar opt, const AppChar *arg)
  switch (opt) {
  case 's':  // new case        
    strict_ = 1;
  /* other cases stay the same */
Finally, we change the call of the StyleEngine constructor in processGrove() to
StyleEngine se(*this, *this, unitsPerInch_, debugMode_, 
               dsssl2_, strict_, extensions);

How to add a new application