Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Initialization: source files are opened and environment configured
  • Parsing: the grammar is used to to produce tree of tokens representing the source code
  • Conversion: An abstract syntax tree (AST) is created from token trees.
  • Semantic Analysis: Performs consistency and validity checks that the grammar can't check for, and resolves classes.
  • Canonicalization: Complete building the AST
  • Instruction Selection: instruction set is chosen, for example java5 or pre java5
  • Class Generation: creates the binary output in memory
  • Output: write the binary output to the file system
  • Finalization: Perform any last cleanup

Generally speaking, there is more type information available later in the phases. If your transformation is concerned with reading the AST, then a later phase where information is more plentiful might be a god good choice. If your transformation is concerned with writing AST, then an earlier phase where the tree is more sparse might be more convenient.

As a particular example, Groovy aggressively and statically types the static properties of a class, as demonstrated here:

Code Block

class Foo {
	static doLog() { log.info("This won't even compile!") }
}
Foo.metaClass.static.log = [info:{ println it }] // Enable the above code to work
/*
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, /Users/robert/dev/workspace/Groovy-WithLog/test/Bogus.groovy: 2: Apparent variable 'log' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attemped to reference a variable in the binding or an instance variable from a static context.
You mispelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'log' but left out brackets in a place not allowed by the grammar.
 @ line 2, column 19.
   	static doLog() { log.info("This won't even compile!") }
                     ^

1 error
*/

So if you want to create an AST transform that creates a static property, you have to hook in before this check is performed: in practice, this means the Conversion phase (Semantic Analysis is where you get busted).  In using a phase that early, though, most types won't be resolved, and so insofar as type resolution is significant (e.g. in checking for annotations of a particular class), it will have to be hand-rolled.

To learn more about what AST is produced in each phase, you can use the AST viewer in Groovy console to explore the output in different phases.