views:

591

answers:

5

Is there any way to override the line numbers in Java (e.g., by using some kind of preprocessor directive)?

I am "compiling" a high-level language, down to Java byte code using Janino. I need compiler errors to report the line from the original file, not the generated Java code.

C# has the #line directive, and I've successfully exploited it to map line numbers from a source file to the compiled result. I need the same for Java.

Thanks!

+2  A: 

Unfortunately, no, there isn't an equivalent #line directive in Java. The best you can do is modify the source after it's been generated by deleting/inserting newlines to match the real source (or modify the code generator). Or, you could modify the line numbers stored in the binary class files after they've been compiled, but that will likely be even more painful.

Adam Rosenfield
+1  A: 

There is no simple solution. One workaround would be to generate a line number map from [your language] to Java when you generate the code. You can pipe the compiler output and use the map to replace Java's line numbers with your line numbers.

jdigital
+5  A: 

I've never seen it used for other than JSP, but JSR-45 was designed to be used for this purpose for any source language. The process involves creating a second file in a special format ("SMAP") that maps line numbers in the original source to line numbers in the generated Java source code.

erickson
+2  A: 

Instead of generating Java code as your intermediate language, you could try using JVM assembler. Jasmin has nice syntax, and you are free to insert .line directives at appropriate places in your code. You can also can also specify the original source file using the the .source directive.

Granted, going the assembler route may be more hassle than it's worth :)

fred-o
+2  A: 

Using Janino you can derive from Scanner and override the location() method. This method returns a Location object. You can override the read() method to look for annotations, within comments for instance (added during code generation), that hold line number information.

You simply pass your scanner to the SimpleCompiler.cook() method and you can control what filename, line and column get reported on error.

Ryan Emerle