Roman Numerals, in your Java
Today’s hack is based on Lukas’s recent work on DSLs. Imagine you could compile and run a Java program that uses Roman numerals.
public class Example {
public static void main(String[] args) {
System.out.println(
MCMLXXVII + XXIV
);
}
}
It can be done—put this 7.5 kb jar in your compiler’s classpath!
% javac -cp roman.jar Example.java Note: 2 roman numerals processed. % java Example 2001 %
Obviously, this jar extends the syntax of Java … close, but not quite. The source code that contains the Roman numerals is already valid Java syntax. It is valid Java with undeclared variables! If you compile it without our small jar, the compiler will tell you that the Roman numerals are undeclared variable names. Thus, our small jar hooks into the compiler, bending JSR 269 beyond its limits, and replaces all roman variables names with integer literals.
Caveat, requires Java 6.
Below the rewrite rule: class Transform extends TreeTranslator, an internal class of the Java compiler. Transform visits all statements in the source code, and replaces each variable whose name matches a Roman numeral with an int literal of the same numeric value.
public class Transform extends TreeTranslator {
@Override
public void visitIdent(JCIdent tree) {
String name = tree.getName().toString();
if (isRoman(name)) {
result = make.Literal(numberize(name));
result.pos = tree.pos;
} else {
super.visitIdent(tree);
}
}
}
Our small jar implements an internal DSL, but an unusual one. We reuse the host language’s original syntax in a creative way that allows us to express new semantics. Lukas refers to this kind of language extension as “pidgin”, since human pidgin languages play in a similar way with natural language.
For the technically inclined, the complete source code is available on SCG subversion.
You may also like
- Hacker’s Guide to the Java Compiler by David Erni
- Javac Hacker Resources, a collection of links
- How to rewrite assertions such that they cannot be turned off!
November 6th, 2008 at 01:01
“bending JSR 269 beyond its limits” is accurate… one of the core precepts of JSR 269 is that it disallows modifying existing classes. Your code is bound to the implementation details of Sun’s javac, and will not work on other compilers (such as Eclipse’s).
Nothing wrong with that, just thought I’d point out that this isn’t a JSR 269 hack, it’s a Sun javac hack. But a fun one!
November 6th, 2008 at 12:59
is there any way to make it work in eclipse?
November 6th, 2008 at 17:58
[...] had no idea you can plug into javac to do nifty things like adding roman numerals to your java [...]
November 6th, 2008 at 18:52
Interesting idea. Of course I don’t know that you’d program this way, but it sure brings up some interesting points on how to create your own custom pre-processor.
And I for sure didn’t realize how simple it is to implement if you know how to do it! Thanks.
November 6th, 2008 at 23:58
@raveman the hack uses internal classes of Sun’s java compiler (see also Walter Harley’s comment). By default eclipse uses its own compiler, you have to change that in the project settings (or use an ant script to compile the code, as I do).
November 7th, 2008 at 10:31
[...] just found this page: For.example [...]
December 5th, 2008 at 09:16
[...] For.example » Blog Archive » Roman Numerals, in your Java [...]
December 9th, 2008 at 21:36
If you want to get your hooks into the Eclipse compiler via its annotation processor, start by creating a new plugin.
-Contribute to the “org.eclipse.jdt.apt.core.annotationProcessorFactory” extension point.
-In the “javax.annotations.processor.Processor” implementation, cast the ProcessingEnvironment to “org.eclipse.jdt.apt.pluggable.core.dispatch.IdeBuildProcessingEnvImpl”
-After that, you’re on your own!
January 4th, 2009 at 11:11
this is awesome. although I wish we could get rid of the backward compatibility of having to still support roman numbers.