Explore Java Infrastructure

Pt

In this course, we will use Java as the object language, i.e. the programs that we are going to transform are written in Java. Of course, you are all familiar with Java and its concrete syntax, but you might not be that familiar with the abstract syntax of the Java language. Before starting with the real transformation assignments, it is a good idea to explore this structure a bit.

Java Syntax

The tool parse-java is used to parse Java programs to an abstract syntax tree represented as an ATerm. Begin with a very simple Java class:

$ echo "class Foo {}" | parse-java | pp-aterm

You can also put the class in a file, which is useful if you are going to try bigger examples. For files, use parse-java -i File.java.

Try to find the corresponding SDF productions in the Java syntax definition (see the navigation bar for a link). Also, lookup these definitions in the Java Language Specification (JLS), which should be easy: the paragraphs of the JLS are mentioned in the syntax definition.

Next, extend the Java program with various code to find out what all these empty lists and Nones are about. For example, introduce an import of java.util.List, declare a package, add a method with some simple statements, let the class extend another class etc. If something is unclear, then lookup the productions in the syntax definition.

Java-front also features a pretty-printer for Java. You can apply this pretty-printer in a pipeline with the parser:

$ parse-java -i Foo.java | pp-java

Java Bytecode

Compile a simple Java source file to a .class file and decompile it using the tool class2aterm:

$ class2aterm -i Foo.class | pp-aterm

Take a brief look at the structure of this aterm. This invocation does not disassemble the code. For this, you have to pass -c as an argument to class2aterm:

$ class2aterm -i Foo.class -c | pp-aterm

Most likely, you will not directly use this tool, but it is good to know that it exists. You will use it a lot indirectly, since the Dryad reflection library uses class2aterm to disassemble Java classes. Dryad also supports a bytecode assembler:

$ class2aterm -i Foo.class -c | aterm2class -o Bar.class

Java Disambiguation

Although you might have the impression that a statement like System.out.println("Hi!") is very clear, it is actually very ambiguous, syntactically speaking. Parse a small Java source file containing this hello world statement and take a look at the representation. Obviously, this representation does not tell us much about the meaning of this program. Therefore, it is difficult to transform this program directly: you cannot just assume a certain meaning for all these ambiguous names.

The Java Language Specification specifies how all ambiguous names should be interpreted (see for example JLS 6.5.2: Reclassification of Contextually Ambiguous Names). To make the implementation of Java transformations more reliable, Dryad implements this reclassification and qualification of names.

Use the tool dryad-front to reclassify the names:

$ dryad-front -i HelloWorld.java | pp-aterm

Take a close look at this example and observe the reclassified names and the qualifiers that have been added to all the names (for example, System is now qualified with java.lang).

In most assignments, we will work on this reclassified and qualified representation of a Java program. Try a few other samples. For example, add an import declaration and find out what happens with local variable and field accesses. Dryad-front accepts multiple source files, but you can also use multiple classes in the same source file of course. Example:

$ dryad-front -i Foo.java Bar.java -o Foo.jtree Bar.jtree

You cannot apply pp-aterm after this invocation (it produces multiple aterms, which is not supported by other tools), that's why output files are used.

Java Type Information

Dryad also provides a type checker, which annotates the expressions of a Java program with their type. The type checker can be enabled by adding the command-line option --tc on:

$ dryad-front --tc on -i HelloWorld.java | pp-aterm

Try a few different examples of method invocations, operators, etc. Note that the type checker does not only annotate types, but also conversions and information about the declaring classes of fields and method accesses. Try an example of a method invocation that invokes a method that is declared in a superclass of the object on which the method is invoked and see what happens with the annotation.

Dryad Model for Java

Exploring the Dryad Model requires some basic knowledge of Stratego, so we will do this later.

See Also