PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/groovy-eclipse/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/compiler/GroovyCompiler.java

http://groovy-eclipse.googlecode.com/
Java | 639 lines | 478 code | 50 blank | 111 comment | 77 complexity | 8bac1da3af884afb0ddc87099249e98f MD5 | raw file
Possible License(s): Apache-2.0
  1. package org.codehaus.groovy.eclipse.core.compiler;
  2. import static org.apache.commons.lang.StringUtils.join;
  3. import static org.codehaus.groovy.eclipse.collections.ListUtil.newList;
  4. import static org.codehaus.groovy.eclipse.collections.MapUtil.hashMap;
  5. import static org.codehaus.groovy.eclipse.collections.MapUtil.newMap;
  6. import static org.codehaus.groovy.eclipse.collections.SetUtil.hashSet;
  7. import static org.codehaus.groovy.eclipse.core.GroovyCore.logException;
  8. import antlr.TokenStreamIOException;
  9. import groovy.lang.GroovyClassLoader;
  10. import java.io.File;
  11. import java.io.FilenameFilter;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.io.PrintWriter;
  15. import java.io.StringWriter;
  16. import java.lang.reflect.Field;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import java.util.regex.Matcher;
  22. import java.util.regex.Pattern;
  23. import org.apache.commons.lang.StringUtils;
  24. import org.apache.tools.ant.BuildException;
  25. import org.codehaus.groovy.antlr.GroovySourceAST;
  26. import org.codehaus.groovy.ast.ASTNode;
  27. import org.codehaus.groovy.ast.ClassNode;
  28. import org.codehaus.groovy.ast.CompileUnit;
  29. import org.codehaus.groovy.ast.ModuleNode;
  30. import org.codehaus.groovy.control.CompilationFailedException;
  31. import org.codehaus.groovy.control.CompilationUnit;
  32. import org.codehaus.groovy.control.CompilerConfiguration;
  33. import org.codehaus.groovy.control.ErrorCollector;
  34. import org.codehaus.groovy.control.MultipleCompilationErrorsException;
  35. import org.codehaus.groovy.control.Phases;
  36. import org.codehaus.groovy.control.ProcessingUnit;
  37. import org.codehaus.groovy.control.SourceUnit;
  38. import org.codehaus.groovy.control.CompilationUnit.ProgressCallback;
  39. import org.codehaus.groovy.control.messages.Message;
  40. import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
  41. import org.codehaus.groovy.control.messages.WarningMessage;
  42. import org.codehaus.groovy.eclipse.collections.ListUtil;
  43. import org.codehaus.groovy.eclipse.core.GroovyCore;
  44. import org.codehaus.groovy.eclipse.core.compiler.internal.CSTParserPluginFactory;
  45. import org.codehaus.groovy.eclipse.core.compiler.internal.ErrorRecoveredCSTParserPluginFactory;
  46. import org.codehaus.groovy.eclipse.core.compiler.internal.ICSTReporter;
  47. import org.codehaus.groovy.syntax.RuntimeParserException;
  48. import org.codehaus.groovy.syntax.SyntaxException;
  49. /**
  50. * High level compiler API suitable for IDE tools. The API compile methods report on all generated artifacts and errors.
  51. * Specific artifacts can be generated, such as CST and/or AST and/or class files.
  52. *
  53. * The notifications sent to the {@link IGroovyCompilationReporter} can be used by the IDE tools to maintain internal
  54. * caches, error markers, and so on.
  55. *
  56. * @author empovazan
  57. */
  58. public class GroovyCompiler implements IGroovyCompiler {
  59. /**
  60. * Reporter that will collect CST errors when error recovery is active.
  61. */
  62. @SuppressWarnings("unchecked")
  63. static class CSTReporter implements ICSTReporter {
  64. final Map< String, GroovySourceAST > mapFileNameToCST = newMap();
  65. final Map< String, List< ? > > mapFileNameToErrors = newMap();
  66. public void generatedCST(final String fileName, final GroovySourceAST ast) {
  67. mapFileNameToCST.put(fileName, ast);
  68. }
  69. public void reportErrors(final String fileName, final List errors) {
  70. mapFileNameToErrors.put(fileName, errors);
  71. }
  72. }
  73. public void compile( final String[] fileNames, final IGroovyCompilerConfiguration configuration, final IGroovyCompilationReporter reporter) {
  74. final CSTReporter cstReporter = new CSTReporter();
  75. final CompilationUnit compilationUnit = initCompile(configuration, cstReporter);
  76. compilationUnit.addSources(fileNames);
  77. compile( compilationUnit, configuration, reporter, cstReporter, fileNames );
  78. }
  79. public void compile(final String fileName, final IGroovyCompilerConfiguration configuration, final IGroovyCompilationReporter reporter) {
  80. compile(new String[] { fileName }, configuration, reporter);
  81. }
  82. public void compile(final String fileName, final InputStream inputStream, final IGroovyCompilerConfiguration configuration, final IGroovyCompilationReporter reporter) {
  83. final CSTReporter cstReporter = new CSTReporter();
  84. final CompilationUnit compilationUnit = initCompile(configuration, cstReporter);
  85. compilationUnit.addSource(fileName, inputStream);
  86. compile( compilationUnit, configuration, reporter, cstReporter, fileName );
  87. }
  88. // Copied from org.codehaus.groovy.ant.Groovyc
  89. protected File createTempDir()
  90. {
  91. try
  92. {
  93. final File tempFile = File.createTempFile( "groovy-generated-", "-java-source" );
  94. tempFile.delete();
  95. tempFile.mkdirs();
  96. return tempFile;
  97. }
  98. catch( final IOException e )
  99. {
  100. throw new BuildException( e );
  101. }
  102. }
  103. // private CompilationUnit initCompile( final IGroovyCompilerConfiguration configuration,
  104. // final CSTReporter cstReporter )
  105. // {
  106. // final ClassLoader classLoader = configuration.getClassLoader();
  107. // final String classPath = configuration.getClassPath();
  108. // final CompilerConfiguration config = createCompilerConfiguration( configuration, cstReporter );
  109. // config.setClasspath( classPath );
  110. // config.setTargetDirectory( configuration.getOutputPath() );
  111. // final Map jointCompilationOptions = new HashMap();
  112. // jointCompilationOptions.put( "stubDir", createTempDir() );
  113. // config.setJointCompilationOptions( jointCompilationOptions );
  114. // final GroovyClassLoader loader;
  115. // if( classLoader != null )
  116. // loader = new GroovyClassLoader( classLoader, config, false );
  117. // else
  118. // loader = new GroovyClassLoader( null, config, true );
  119. //
  120. // return new JavaAwareCompilationUnit( config, loader );
  121. // }
  122. private CompilationUnit initCompile( final IGroovyCompilerConfiguration configuration,
  123. final CSTReporter cstReporter )
  124. {
  125. final ClassLoader classLoader = configuration.getClassLoader();
  126. final String classPath = configuration.getClassPath();
  127. final CompilerConfiguration config = createCompilerConfiguration( configuration, cstReporter );
  128. config.setClasspath( classPath );
  129. config.setTargetDirectory( configuration.getOutputPath() );
  130. final GroovyClassLoader loader;
  131. if( classLoader != null )
  132. loader = new GroovyClassLoader( classLoader, config, false );
  133. else
  134. loader = new GroovyClassLoader( null, config, true );
  135. final CompilationUnit compilationUnit = new CompilationUnit( config, null, loader );
  136. return compilationUnit;
  137. }
  138. private CompilerConfiguration createCompilerConfiguration(final IGroovyCompilerConfiguration configuration,
  139. final CSTReporter cstReporter) {
  140. CompilerConfiguration config;
  141. if (configuration.isErrorRecovery() && (configuration.getBuildCST() || configuration.getBuildAST() || configuration.isForceBuild())) {
  142. config = new CompilerConfiguration();
  143. config.setPluginFactory(new ErrorRecoveredCSTParserPluginFactory(cstReporter));
  144. } else if (configuration.getBuildCST()) {
  145. config = new CompilerConfiguration();
  146. config.setPluginFactory(new CSTParserPluginFactory(cstReporter));
  147. } else {
  148. config = new CompilerConfiguration();
  149. }
  150. config.setOutput(new PrintWriter(System.err));
  151. config.setWarningLevel(WarningMessage.PARANOIA);
  152. return config;
  153. }
  154. private void compile( final CompilationUnit compilationUnit,
  155. final IGroovyCompilerConfiguration configuration,
  156. final IGroovyCompilationReporter reporter,
  157. final CSTReporter cstReporter,
  158. final String... fileNames )
  159. {
  160. setProgressCallback(compilationUnit);
  161. // CompilerConfiguration cc = new CompilerConfiguration();
  162. // cc.setDebug(true);
  163. // JavaStubCompilationUnit compilation = new JavaStubCompilationUnit(cc,
  164. // compilationUnit.getClassLoader(),
  165. // compilationUnit.getConfiguration().getTargetDirectory());
  166. //
  167. // for (int i=0;i<fileNames.length;i++){
  168. // compilation.addSourceFile(new File(fileNames[i]));
  169. // }
  170. // compilation.compile(Phases.CONVERSION);
  171. int phases = 0;
  172. if (configuration.getBuildCST()) {
  173. phases = Phases.PARSING;
  174. }
  175. if (configuration.getBuildAST()) {
  176. phases = Phases.SEMANTIC_ANALYSIS;
  177. if (configuration.getResolveAST()) {
  178. phases = Phases.CANONICALIZATION;
  179. }
  180. if(configuration.getUnResolvedAST()){
  181. phases = Phases.CONVERSION;
  182. }
  183. }
  184. if (configuration.getBuildClasses() && (!configuration.isErrorRecovery() || configuration.isForceBuild())) {
  185. phases = Phases.ALL;
  186. }
  187. if (phases == 0) {
  188. return;
  189. }
  190. Exception compileException = null;
  191. try {
  192. compilationUnit.compile(phases);
  193. } catch (final Exception e) {
  194. compileException = e;
  195. }
  196. // Now report
  197. if (compileException == null) {
  198. // There may be errors which were reported, but were recovered. They are still reported.
  199. reportBuild(compilationUnit, configuration, fileNames, reporter, cstReporter);
  200. } else {
  201. // These are fatal compile errors.
  202. reportErrors(reporter, configuration, fileNames, compileException);
  203. }
  204. }
  205. @SuppressWarnings("unchecked")
  206. private void reportBuild(final CompilationUnit compilationUnit, final IGroovyCompilerConfiguration configuration, final String[] fileNames,
  207. final IGroovyCompilationReporter reporter, final CSTReporter cstReporter) {
  208. final CompileUnit ast = compilationUnit.getAST();
  209. final List< ? > moduleList = newList( ast.getModules() );
  210. // FUTURE: possible control of prune/no prune in the configuration.
  211. pruneModuleList(moduleList, fileNames);
  212. if (moduleList.size() > 0) {
  213. reportAll(compilationUnit, configuration, moduleList, fileNames, reporter, cstReporter);
  214. } else {
  215. reportCSTs(configuration, reporter, cstReporter);
  216. }
  217. }
  218. private void reportAll(final CompilationUnit compilationUnit, final IGroovyCompilerConfiguration configuration,
  219. final List moduleList, final String[] fileNames, final IGroovyCompilationReporter reporter, final CSTReporter cstReporter) {
  220. final File targetDirectory = compilationUnit.getConfiguration().getTargetDirectory();
  221. reporter.beginReporting();
  222. try {
  223. for (final Iterator iter = moduleList.iterator(); iter.hasNext();) {
  224. final ModuleNode moduleNode = (ModuleNode) iter.next();
  225. final String fileName = moduleNode.getDescription();
  226. final String reportFileName = fileName.replaceAll("\\\\\\\\", "\\\\");
  227. reporter.beginReporting(reportFileName);
  228. try {
  229. if (configuration.getBuildCST() || configuration.isErrorRecovery()) {
  230. // First the errors.
  231. final List errors = cstReporter.mapFileNameToErrors.get(fileName);
  232. if (errors != null) {
  233. reportCSTErrors(reportFileName, errors, reporter);
  234. }
  235. // Now the CST.
  236. final GroovySourceAST cst = cstReporter.mapFileNameToCST.get(fileName);
  237. reporter.generatedCST(reportFileName, cst);
  238. }
  239. if (configuration.getBuildAST()) {
  240. reporter.generatedAST(reportFileName, moduleNode);
  241. }
  242. if (configuration.getBuildClasses()) {
  243. reporter.generatedClasses(reportFileName, makeClassNameArray(moduleNode), makeClassFilePathArray(
  244. moduleNode, targetDirectory));
  245. }
  246. } finally {
  247. reporter.endReporting(fileName);
  248. }
  249. }
  250. } finally {
  251. reporter.endReporting();
  252. }
  253. }
  254. private void reportCSTErrors(final String fileName, final List errors, final IGroovyCompilationReporter reporter) {
  255. for (final Iterator iter = errors.iterator(); iter.hasNext(); ) {
  256. final Map map = (Map) iter.next();
  257. final String error = (String) map.get("error");
  258. final int line = ((Integer)map.get("line")).intValue();
  259. final int column = ((Integer)map.get("column")).intValue();
  260. reporter.compilationError(fileName, line, column, column, error, null);
  261. }
  262. }
  263. private void reportCSTs(final IGroovyCompilerConfiguration configuration, final IGroovyCompilationReporter reporter,
  264. final CSTReporter cstReporter) {
  265. reporter.beginReporting();
  266. try {
  267. if (configuration.getBuildCST()) {
  268. final Set setOfFileNames = cstReporter.mapFileNameToCST.keySet();
  269. for (final Iterator iter = setOfFileNames.iterator(); iter.hasNext();) {
  270. final String fileName = (String) iter.next();
  271. final String reportFileName = fileName.replaceAll("\\\\\\\\", "\\\\");
  272. reporter.beginReporting(reportFileName);
  273. try {
  274. // First the errors.
  275. final List errors = cstReporter.mapFileNameToErrors.get(fileName);
  276. if (errors != null) {
  277. reportCSTErrors(reportFileName, errors, reporter);
  278. }
  279. // Now the CST.
  280. final GroovySourceAST cst = cstReporter.mapFileNameToCST.get(fileName);
  281. if (cst != null) {
  282. reporter.generatedCST(reportFileName, cst);
  283. }
  284. } finally {
  285. reporter.endReporting(reportFileName);
  286. }
  287. }
  288. }
  289. } finally {
  290. reporter.endReporting();
  291. }
  292. }
  293. /**
  294. * Remove ModuleNodes not in the list of files that were built. Given a list of ModuleNodes, some of them will not
  295. * be in the list of file names that were built. This is because the Groovy compiler creates ModuleNodes during
  296. * building our files in the list. So prune the list.
  297. *
  298. * @param moduleList
  299. * @param builtFileNames
  300. */
  301. private void pruneModuleList( final List moduleList,
  302. final String[] builtFileNames )
  303. {
  304. // Set fileNamesLookup = new HashSet(Arrays.asList(builtFileNames));
  305. final Set< File > fileNamesLookup = hashSet();
  306. for( final String fileName : builtFileNames )
  307. fileNamesLookup.add( new File( fileName ) );
  308. for( final Iterator iter = moduleList.iterator(); iter.hasNext(); )
  309. {
  310. final ModuleNode moduleNode = ( ModuleNode )iter.next();
  311. if( !fileNamesLookup.contains( new File( moduleNode.getDescription() ) ) )
  312. iter.remove();
  313. }
  314. }
  315. /**
  316. * @param moduleNode
  317. * @return An array of fully qualified class names.
  318. */
  319. private String[] makeClassNameArray(final ModuleNode moduleNode) {
  320. final List classes = moduleNode.getClasses();
  321. final String[] ret = new String[classes.size()];
  322. for (int i = 0; i < ret.length; ++i) {
  323. ret[i] = ((ClassNode) classes.get(i)).getName();
  324. }
  325. return ret;
  326. }
  327. /**
  328. * Returns a list of class files generated for a specific module node.
  329. *
  330. * @param moduleNode
  331. * @param targetDirectory
  332. * The target directory in which the class files were generated.
  333. * @return Array of canonical paths to the class files.
  334. * @throws IOException
  335. */
  336. private String[] makeClassFilePathArray(final ModuleNode moduleNode, final File targetDirectory) {
  337. try {
  338. final List classes = moduleNode.getClasses();
  339. final List< String > ret = newList();
  340. final String outputPath = targetDirectory.getCanonicalPath();
  341. for (final Iterator iter = classes.iterator(); iter.hasNext();) {
  342. final ClassNode classNode = (ClassNode) iter.next();
  343. final String partialPath = classNode.getName().replace('.', File.separatorChar);
  344. final String classFilePath = outputPath + File.separatorChar + partialPath + ".class";
  345. ret.add(classFilePath);
  346. final String searchDirectory = classFilePath.substring(0, classFilePath.lastIndexOf(File.separatorChar));
  347. final String classNamePrefix = classFilePath.substring(
  348. classFilePath.lastIndexOf(File.separatorChar) + 1, classFilePath.lastIndexOf('.')) + '$';
  349. final File[] files = new File(searchDirectory).listFiles(new FilenameFilter() {
  350. public boolean accept(final File dir, final String name) {
  351. return name.startsWith(classNamePrefix);
  352. }
  353. });
  354. for (int i = 0; i < files.length; ++i) {
  355. ret.add(files[i].getCanonicalPath());
  356. }
  357. }
  358. return ret.toArray(new String[ret.size()]);
  359. } catch (final IOException e) {
  360. throw new RuntimeException("Error getting canonical paths.");
  361. }
  362. }
  363. private void setProgressCallback(final CompilationUnit unit) {
  364. unit.setProgressCallback(new ProgressCallback() {
  365. @Override
  366. public void call(final ProcessingUnit context, final int phase) throws CompilationFailedException {
  367. switch (phase) {
  368. case Phases.PARSING:
  369. break;
  370. case Phases.CANONICALIZATION:
  371. break;
  372. case Phases.CLASS_GENERATION:
  373. break;
  374. }
  375. }
  376. });
  377. }
  378. /**
  379. * Handle compilation errors. This are the errors collected while compiling the source files in the file list.
  380. * Occasionally the exception is an internal compiler error.
  381. *
  382. * @param reporter
  383. * @param configuration
  384. *
  385. * @param fileNames
  386. * @param e
  387. */
  388. private void reportErrors( final IGroovyCompilationReporter reporter,
  389. final IGroovyCompilerConfiguration configuration,
  390. final String[] fileNames,
  391. final Exception e )
  392. {
  393. // TODO: emp - some files may have been built before errors. These
  394. // should be reported.
  395. // How to do this? Perhaps collect info in the ProgressCallback?
  396. if( e instanceof MultipleCompilationErrorsException )
  397. {
  398. final Map mapFileNamesToExceptions = mapFileNamesToExceptions( fileNames, ( MultipleCompilationErrorsException )e );
  399. reportErrors( reporter, mapFileNamesToExceptions );
  400. return;
  401. }
  402. // TODO: emp - possible to get name of the actual file that was
  403. // being compiled?
  404. // Perhaps by catching the current file being built in the progress
  405. // call back, but
  406. // how to link it to the exception?
  407. logException( "Error compiling " + join( fileNames, ", " ), e );
  408. }
  409. /**
  410. * @param fileNames
  411. * @param e
  412. * @return A mapping from a file name to a list of exceptions.
  413. */
  414. @SuppressWarnings("unchecked")
  415. private static Map mapFileNamesToExceptions( final String[] fileNames,
  416. final MultipleCompilationErrorsException e )
  417. {
  418. final Map< String, List< Exception > > mapFileNamesToExceptions = hashMap();
  419. final ErrorCollector collector = e.getErrorCollector();
  420. for( int i = 0; i < collector.getErrorCount(); i++ )
  421. {
  422. final Exception exception = collector.getException( i );
  423. final String fileName = getFilenameFromException( exception );
  424. if( StringUtils.isNotBlank( fileName ) )
  425. {
  426. addFileToExceptionMap( fileName, exception, mapFileNamesToExceptions );
  427. continue;
  428. }
  429. // file is null if the file with errors is an external file, and not
  430. // one in the change set.
  431. // TODO: emp - it the above statement true? AFAIK, it is because of
  432. // an internal compiler error. And if the above
  433. // is true, there should be some sort of notification.
  434. final SourceUnit[] units = getOwnersFromMessage( collector.getError( i ) );
  435. for( int j = 0; j < units.length; j++ )
  436. {
  437. final SourceUnit unit = units[ j ];
  438. addFileToExceptionMap( unit.getName().replaceAll( "\\\\\\\\", "\\\\" ), exception, mapFileNamesToExceptions );
  439. }
  440. }
  441. return mapFileNamesToExceptions;
  442. }
  443. private static void addFileToExceptionMap( final String fileName,
  444. final Exception exception,
  445. final Map< String, List< Exception > > mapFileNamesToExceptions )
  446. {
  447. if( StringUtils.isBlank( fileName ) )
  448. return;
  449. if( !mapFileNamesToExceptions.containsKey( fileName ) )
  450. mapFileNamesToExceptions.put( fileName, newList( new Exception[ 0 ] ) );
  451. mapFileNamesToExceptions.get( fileName ).add( exception );
  452. }
  453. @SuppressWarnings("unchecked")
  454. private static SourceUnit[] getOwnersFromMessage( final Message message )
  455. {
  456. try
  457. {
  458. if( message instanceof SyntaxErrorMessage )
  459. {
  460. final Field field = message.getClass().getDeclaredField( "source" );
  461. field.setAccessible( true );
  462. final SourceUnit sourceUnit = ( SourceUnit )field.get( message );
  463. if( sourceUnit == null )
  464. return new SourceUnit[ 0 ];
  465. return new SourceUnit[] { sourceUnit };
  466. }
  467. final Field field = message.getClass().getDeclaredField( "owner" );
  468. field.setAccessible( true );
  469. final ProcessingUnit processingUnit = ( ProcessingUnit )field.get( message );
  470. if( processingUnit == null )
  471. return new SourceUnit[ 0 ];
  472. if( processingUnit instanceof SourceUnit )
  473. return new SourceUnit[] { ( SourceUnit )processingUnit };
  474. // If not a SourceUnit, it should be a CompilationUnit
  475. final CompilationUnit compilationUnit = ( CompilationUnit )processingUnit;
  476. final List< SourceUnit > sources = ListUtil.array();
  477. final Iterator< SourceUnit > iterator = compilationUnit.iterator();
  478. while( iterator.hasNext() )
  479. sources.add( iterator.next() );
  480. return sources.toArray( new SourceUnit[ 0 ] );
  481. }
  482. catch( final SecurityException e )
  483. {
  484. GroovyCore.logException( e.getMessage(), e );
  485. }
  486. catch( final NoSuchFieldException e )
  487. {
  488. GroovyCore.logException( e.getMessage(), e );
  489. }
  490. catch( final IllegalArgumentException e )
  491. {
  492. GroovyCore.logException( e.getMessage(), e );
  493. }
  494. catch( final IllegalAccessException e )
  495. {
  496. GroovyCore.logException( e.getMessage(), e );
  497. }
  498. return null;
  499. }
  500. /**
  501. * @param reporter
  502. * @param mapFileNamesToExceptions
  503. * Map from a file name to a list of compilation error exceptions for the file name.
  504. */
  505. private void reportErrors( final IGroovyCompilationReporter reporter,
  506. final Map mapFileNamesToExceptions )
  507. {
  508. for( final Iterator iter = mapFileNamesToExceptions.keySet().iterator(); iter.hasNext(); )
  509. {
  510. final String fileName = ( String )iter.next();
  511. final List exceptions = ( List )mapFileNamesToExceptions.get( fileName );
  512. reporter.beginReporting( fileName );
  513. try
  514. {
  515. for( final Iterator iterException = exceptions.iterator(); iterException.hasNext(); )
  516. {
  517. final Exception exception = ( Exception )iterException.next();
  518. if( exception == null )
  519. continue;
  520. reportError( reporter, fileName, exception );
  521. }
  522. }
  523. finally
  524. {
  525. reporter.endReporting( fileName );
  526. }
  527. }
  528. }
  529. private static String getFilenameFromException( final Exception exception )
  530. {
  531. String filename = "";
  532. if( exception instanceof SyntaxException )
  533. filename = ( ( SyntaxException )exception ).getSourceLocator();
  534. else if( exception instanceof RuntimeParserException )
  535. filename = ( ( RuntimeParserException )exception ).getModule().getDescription();
  536. if( StringUtils.isNotBlank( filename ) )
  537. {
  538. // Replaces double backslashes with single ones.
  539. // Backslash regex: \\, quoted "\\\\", two of them "\\\\\\\\".
  540. return filename.replaceAll( "\\\\\\\\", "\\\\" );
  541. }
  542. return filename;
  543. }
  544. private void reportError(final IGroovyCompilationReporter reporter, final String fileName, final Exception exception) {
  545. int line, startCol, endCol;
  546. String message;
  547. StringWriter traceWriter = new StringWriter();
  548. if (exception instanceof SyntaxException) {
  549. final SyntaxException se = (SyntaxException) exception;
  550. line = se.getLine();
  551. startCol = se.getStartColumn();
  552. endCol = se.getEndColumn();
  553. message = exception.getMessage();
  554. se.printStackTrace(new PrintWriter(traceWriter));
  555. } else if (exception instanceof RuntimeParserException
  556. && ((RuntimeParserException) exception).getNode() != null) {
  557. final RuntimeParserException rex = (RuntimeParserException) exception;
  558. // Need to extract info from the node.
  559. final ASTNode node = rex.getNode();
  560. line = node.getLineNumber();
  561. startCol = node.getColumnNumber();
  562. endCol = node.getLastColumnNumber();
  563. message = rex.getMessageWithoutLocationText();
  564. // After newline is the AST node where the error was found.
  565. final int ix = message.indexOf("\n");
  566. if (ix != -1)
  567. message = message.substring(0, ix);
  568. traceWriter = new StringWriter();
  569. rex.printStackTrace(new PrintWriter(traceWriter));
  570. } else if (exception instanceof TokenStreamIOException) {
  571. // Handle an internal compiler exception.
  572. message = exception.getMessage();
  573. line = startCol = endCol = -1;
  574. final Pattern pattern = Pattern.compile("\\w+:\\s*(\\d+)\\s*\\w+:\\s*(\\d+)\\s*");
  575. final Matcher matcher = pattern.matcher(message);
  576. if (matcher.find() && matcher.groupCount() == 2) {
  577. line = Integer.parseInt(matcher.group(1));
  578. startCol = Integer.parseInt(matcher.group(2));
  579. endCol = startCol + 1;
  580. }
  581. exception.printStackTrace(new PrintWriter(traceWriter));
  582. } else {
  583. line = startCol = endCol = -1;
  584. message = exception.getMessage();
  585. exception.printStackTrace(new PrintWriter(traceWriter));
  586. }
  587. reporter.compilationError(fileName, line, startCol, endCol, message, traceWriter.toString());
  588. }
  589. }