Class CustomIntLiteral implements the "language": Fields store the source ("one") and the source position. Method resolve(..) looks up the source in an array of number words and uses the index as the literal's value. Nothing magic. Plain Java extension of org.eclipse.jdt.internal.compiler.ast.IntLiteral.

All magic is in class SyntaxAdaptor: This team contains two roles for the two stages of adaptation:

Stage 1

Role ScannerAdaptor is responsible for intercepting the detection of a '<' during scanning. This is the full source code of this role:
protected class ScannerAdaptor playedBy Scanner {

"class ScannerAdaptor playedBy Scanner" denotes that this class is a role adapting the given class Scanner.
lines containing "-> get" or "-> set" define a "callout" binding whereby the role can access members of its base class Scanner, here get-/set-accessors for some fields are defined.
the line containing "<- replace" defines a "callin" binding whereby the role intercepts calls to the method at the right hand side, and replaces these calls with calls to the method at the left hand side (side note: for a "replace" binding the role method bound here has to be marked with a "callin" modifier).
inside the role method "getNextToken" the only special syntax is "base.getNextToken()" which is used to invoke the original method being intercepted (here: from Scanner)

The logic in this method simply checks if we found a LESS token, if it is followed by '%', and searches the terminating '%' '>'. The source fragment between the special delimiters is extracted and passed to the second stage, which is the responsibility of an InternalAdaptor.

Stage 2

Class InternalAdaptor is both a role of SyntaxAdaptor and also a team with a nested role. The reason for making this a team is: now it has the capability to be activated at certain points during runtime (see the activate() call immediately following the instantion of InnerAdaptor). I.e., when stage 1 has detected a <% something %> string, it activates a fresh instance of InnerAdaptor which enables a callin binding in the nested role ParserAdaptor. This stage is responsible for feeding some hand-crafted AST into the parser. The InnerAdaptor with its nested role looks like this:
protected team class InnerAdaptor {
char[] source;
int start, end;
protected InnerAdaptor(char[] source, int start, int end) {
this.source = source;
this.start = start;
this.end = end;
}

@SuppressWarnings("basecall")
callin void consumeToken(int type) {
if (type == TerminalTokens.TokenNamenull) {
InnerAdaptor.this.deactivate(); // this inner adaptor has done its job, no longer intercept
// TODO analyse source to find what AST should be created
Expression replacement = new CustomIntLiteral(source, start, end);
// feed custom AST into the parser:
this.pushOnExpressionStack(replacement);
return;
}
// shouldn't happen: only activated when scanner returns TokenNamenull
base.consumeToken(type);
}
}
}
We see the same constructs (playedBy, callout, callin, base-call).
The logic is: after the ScannerAdaptor has detected the special tokens it activated an InnerAdaptor and returns a null token, which tells the Parser we saw a legal expression token. This null token is now intercepted in consumeToken(int). Instead of creating a null literal a CustomIntLiteral is constructed and pushed on the expression stack. Well, at this point the instance of InnerAdaptor has done its one-shot job, so it is deactivated again leaving it as prey for the garbage collector.

We're done programming!

Now we only have to tell OT/Equinox about our teams using the following snippet in plugin.xml:
<extension
point="org.objectteams.otequinox.aspectBindings">
<aspectBinding
icon=" platform:/plugin/org.objectteams.otdt.ui/icons/ot/calloutbin ding_obj.gif ">
<basePlugin
icon=" platform:/plugin/org.eclipse.pde.ui/icons/obj16/plugin_obj.g if "
id="org.eclipse.jdt.core">
</basePlugin>
<team
activation="ALL_THREADS"
class="embedding.jdt.SyntaxAdaptor"
icon=" platform:/plugin/org.objectteams.otdt.ui/icons/ot/team_obj.g if ">
</team>
<team
activation="NONE"
class="embedding.jdt.SyntaxAdaptor$__OT__InnerAdaptor"
icon=" platform:/plugin/org.objectteams.otdt.ui/icons/ot/team_obj.g if ">
</team>
</aspectBinding>
</extension>
This anounces that base plugin org.eclipse.jdt.core will be adapted by two teams, SyntaxAdaptor and InnerAdaptor (ignore the man behind the curtain, the __OT__ prefix shouldn't be needed here, to be fixed soon).
The first team is globally activated (ALL_THREADS) while the second awaits programmatic activation (NONE).

Running

Import this plugin into a workspace of your OTDT installation.
Launch a runtime workbench
In the runtime workbench

When playing with this I accidentally declared foo to return char[]. Guess what: the JDT found that '<% one %>' is of type int and offered to adjust foo() to returning int. Quickfix offered at the place of your special syntax :)

I think this was fun! Starting from here, integrating more serious sub-languages into the JDT should be mostly straight-forward.

Hi Stephan,
I tried your example and it is potentially wonderful to get what we have in mind.
Of course I know that this is a first step but a lot of aspects will be involved to have a complete editor..anyway I'm going to study more about OT/J and AST. I'll definitively come back to you, hoping in your help.
Thanks,
Giovanni

> I tried your example and it is potentially wonderful to get what we have
> in mind.

I'm glad you like it :)

> Of course I know that this is a first step but a lot of aspects will be
> involved to have a complete editor..anyway I'm going to study more about
> OT/J and AST. I'll definitively come back to you, hoping in your help.

I have been working in the area. But in my case it would be also interesting to adjust the org.eclipse.jdt.core.dom AST, since this is the AST which other plugins use to manipulate the source.

Following Stephans example i have been adapting the dom AST with OT/J.

The primary class to adapt is the ASTConverter. This class converts the compiler AST to a dom AST. My goal was to create my own special NumberLiteral Node (DomCustomIntLiteral). Due to access restrictions in the dom package I had to adapt the NumberLiteral Node with a Role instead of just extending it. The second step was to let the ASTConverter create DomCustomIntLiteral instead of NumberLiteral for each CustomIntLiteral Node in the compiler AST.

To use this modified AST you would either need to store all information in Properties to make them available for all programs using this AST or you would need to offer an API to make the Roles available.

This works fine. But there is one problem left:

The DomCustomIntLiteral adapts all NumberLiterals, which it shouldn't. The DomCustomIntLiteral should only be played by the NumberLiterals which got created by the ASTConverter. Is there a way to fix this? I have been looking into Baseguards, but those would need an information in the Base to decide whether this Node is a regular NumberLiteral or a DomCustomIntLiteral.