PROPOSAL: Compiletime information access

rssh at gradsoft.com.ua rssh at gradsoft.com.ua
Tue Mar 24 06:06:21 PDT 2009


AUTHOR:  Ruslan Shevchenko

OVERVIEW:

 FEATURE SUMMARY:

   Add API to access compile-time context of current compiled element from
 programs and annotation processors.

 MAJOR ADVANTAGE:

   Now compile time properties are unaccessible for programmer. This meaning
 that some functionality (such as access to location of file and line) is
 accessible only from debug version of program with technique, which is not
 officially supported, some (such as access to time of compilation or
  to binding context of current program location) is not avaible at all.

 MAJOR DISADVANTAGE

   Inaccurate usage of this feature can cause producing of unmaintable code.

 ALTERNATIVES:

   External preprocessing of java sources.

EXAMPLES

SIMPLE EXAMPLE:

Example 1

  if (traceCondigion) {
    log.trace(Compiletime.getFileName()+":"+
              Compiletime.getLineNumber());
  }

Example 2

  if (system.currentTimeMillis() - Compiletime.getTimeMillis() > 86400) {
     System.out.println("This file was compiled more than day ago");
  }

Example 3

  System.out.println("Superprogram by AAA AC, version:"+
                                      Compiletime.exec("svnversion"));

ADVANCED EXAMPLE:

Example 1
  // assuming that multiline strings are implemented:

  int a=0;
  int b=1;
  Binding bindings = Compiletime.getInstance().getCurrentBindings();
  ScriptEngine velocity = ScriptEngineManager.get("velocity");
  try {
    String fname = Compiletime.getFileName();
    int    line  = Compiletime.getLineNumber();
    String s = velocity.eval("""
    #if ($a==$b)
        Something interesting here may be,
       Are you know that value of b is $b ?
    #else
       no mistics here.
    #end
    """,
    bindings);
  } catch (ScriptException ex){
     Sytem.err.println("error in inline velocity in "+fname+", "
                       "line "+line+1+ex.getLineNumber());
  }


Example 2

  boolean isDemo = (Compiletime.eval(Properties.class,
                                   "getProperty","is.demo")!=null);

  if (!isDemo) {
    String key = (String)Compiletime.eval(GenerateUniqueKey.class,
                                        "generate");
    LoadNotDemoClass();
  }


DETAILS:



 Add to Java Library pseudo-objects java.lang.Compiletime with access to
compile-time properties and next signature:

public class Compiletime
{
   /**
    * get filename of compiled call.
    * in case of generated source and avaible JSR-45 SMAP file
    * return file name of translated-source.
    **/
   public static String getFileName();

   /**
    * get line number of compiled call.
    * in case of generated source and avaible JSR-45 SMAP file
    * return line number in translated-source.
    **/
   public static int getLineNumber();

   /**
    * get class name where this call is placed.
    * in case of generated source and avaible JSR-45 SMAP file
    * return class name in translated-source.
    **/
   public static int getClassName();

   /**
    * get method name where this call is placed.
    * in case of generated source and avaible JSR-45 SMAP file
    * return method name in translated-source.
    **/
   public static int getMethodName();


   /**
    * generate JSR223 bindings for given names in current compilation
    *context.
    *Names array must be empty or consists from string literals.
    **/
   public static Bindings getBindings(String ... names)


   /**
    * get time of compilation in miliseconds.
    **/
   public static long getTimeMillis();

   /**
    * Execute os command in compile-time.
    *@command - must be a string literal or result of call of Compiletime
    * method, otherwise compile-time error is thrown
    **/
   public static String exec(String command)
   /**
    *  call java class at compile-time.
    *During processing this directive, compiler will
    *1. determinate, if class available in user path.
    *2. determinate, if exists method with appropriative number and types
    *  of parameters.
    *3. If such method is static - call one, otherwise
    *  3.1 if class have default constructor - create instance of object
    *      (otherwise throw compile-time error)
    *  3.2. Call methid with new-created instance.
    *  3.3. If method return some result - substitute output to result,
    *       on exception throw compile-time error.
    *@param classLiteral - must be a class literal for object to call.
    *@param methodName - must be a string literal with name of method to
call.
    *@param parameters - parameters of method to call. Must be a literals, or
    *    calls of Compiletime methods.
    **/
   public static Object eval(Class<?> classLiteral, String methodName,
Object .. params);

}



COMPILATION:

 During compilation calls to compile time are changed to generation of
appriative constant expressions.

String x = Compiletime.getFileName();
changed to
String x = "com/mycompany/package/MyClass.java";

int x = Compiletime.getLinNumber();
 changed to
int x = 33;

String x = getClassName()
 changed to
String x = "com.mycompany.package.MyClass";


class X
{
  int p1;
  String p2;

  ...
  public void doSomething(int x, int y)
  {
    int local = x+y;
    Bindings bindings = Compiletime.getBindings();
    evalSomeScript(bindings);
  }

}


 will translated to

class X
{
  int p1;
  String p2;
  ...

  public void doSomething(int x, int y)
  {
    int local = x+y;
    SimpleBinding binding=(SimpleBinging uniqueName= new SimpleBinding();
                           uniqueName.put("this",this);
                           uniqueName.put("p1",p1);
                           uniqueName.put("p2",p2);
                           uniqueName.put("x",x);
                           uniqueName.put("y",y);
                           uniqueName.put("local",local);
                           uniqueName );
    evalSomeScript(bindings);
  }


}

 (assuming that Block Expressions for Java will be avaible. If not - it
will be necessory create own implementation of Bindings as part of
library).

exec will be changed to Sting literal, with result of execution, i. e.
on Unix
String compiledBy = Compiletime.eval("whoami");
whill be translated to 'rssh'

At last eval call is translated to
 - appropriative literal, if result of eval is primitive type or boxed
   primitivew type.
 - Call of code to unserialize constant byte array, which as serialized
   during compilation
 or throw compile-time error is object is not primitive type and not
implements Serializable.

JLS changes: current scope of JLS is not touched.

Btw, may be add to JLS chapter with name 'Compilation process' where
describe:
 - high level description of transforming source code to JVM classes.
 - process of automatic loading of annotation processors and when ones are
used.
 - this API.


TESTING:

 Special cases are:
  *  compability with JSR45
  *  testing of exec function is

LIBRARY SUPPORT:
  None, or adding two classes (for Bindings implementation with filling in
constructor and Unserializing Object utility) in depends of avaibility
of block expressions for Java

 (May be exists sence add methods for retrieveing source location (i.e. file
 name and line number retrieving) to javax.lang.model.element.Element to
 support better diagnostics.

REFLECTIVE APIS: None

OTHER CHANGES: None

MIGRATION: None

COMPABILITY
 None

REFERENCES

 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4411102
 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6439965
 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4649007

IMPLEMENTATION URL (optional)

 None yet.








More information about the coin-dev mailing list