Twitter icon.
Random notes on software, programming and languages.
By Adrian Kuhn

Archive for the ‘Beyond JSR 269’ Category

Check printf at compile-time


Monday, March 16th, 2009

Since the introduction of #printf in Java 1.5, I always wished to check my format strings and their arguments at compile-time.

Now, it can be done.

The following compiler-plugin checks format string and format arguments of any call to #printf and #format. Of course, checking is limited to format-strings known at compile time.

Just put printf.jar in your classpath (works with javac only!)

javac -classpath printf.jar Example.java

Since there are numerous #printf and #format methods in the Java API, any method with one of said names and with parameters of type String and Object[] is checked. (A cleaner solution would use a @Printf annotation to mark these methods. Alas, I cannot touch the Java API just like that.)

The above plugin works with javac only. Why? Annotation processing is done before type attribution and thus type information is not available to a JSR 269 plugin. However, checking the type of format arguments cannot be done without type information. Thus, what I do is to manually invoke the compiler’s type attribution phase. This is done using the internal Attr component as follows.

import com.sun.tools.javac.comp.Attr;

@SupportedAnnotationTypes("*")
public class Printf extends AbstractProcessor {

    private Attr attr;

    public synchronized void init(ProcessingEnvironment processingEnv) {
        attr = Attr.instance(((JavacProcessingEnvironment) processingEnv).getContext());
        ...
    }

    public boolean process(Set annotations, RoundEnvironment roundEnv) {
        for (Element each: roundEnv.getRootElements()) {
            if (each.getKind() == ElementKind.CLASS) {
                attr.attribClass(null, (ClassSymbol) each);
                ...
           }
        }
    }

    ...

PS, type information is discarded after each annotation processor round. It is thus safe to apply type manipulating changes to the AST from within an annotation processor, since after the plugins have been run, type information is re-attributed again from scratch.

For the full sources, please refer to /Sources/b/Printf on the SCG repository.

Have fun!

Roman Numerals, in your Java


Wednesday, November 5th, 2008

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

For.example is Digg proof thanks to caching by WP Super Cache!