1 46 47 package org.codehaus.groovy.control; 48 49 import java.io.File ; 50 import java.io.IOException ; 51 import java.io.Reader ; 52 import java.lang.reflect.Constructor ; 53 import java.lang.reflect.InvocationTargetException ; 54 import java.net.URL ; 55 import java.util.List ; 56 57 import org.codehaus.groovy.GroovyBugError; 58 import org.codehaus.groovy.ast.ClassNode; 59 import org.codehaus.groovy.ast.FieldNode; 60 import org.codehaus.groovy.ast.MethodNode; 61 import org.codehaus.groovy.ast.ModuleNode; 62 import org.codehaus.groovy.ast.stmt.BlockStatement; 63 import org.codehaus.groovy.ast.stmt.Statement; 64 import org.codehaus.groovy.control.io.FileReaderSource; 65 import org.codehaus.groovy.control.io.ReaderSource; 66 import org.codehaus.groovy.control.io.StringReaderSource; 67 import org.codehaus.groovy.control.io.URLReaderSource; 68 import org.codehaus.groovy.control.messages.LocatedMessage; 69 import org.codehaus.groovy.control.messages.Message; 70 import org.codehaus.groovy.control.messages.SimpleMessage; 71 import org.codehaus.groovy.control.messages.SyntaxErrorMessage; 72 import org.codehaus.groovy.control.messages.WarningMessage; 73 import org.codehaus.groovy.syntax.CSTNode; 74 import org.codehaus.groovy.syntax.Reduction; 75 import org.codehaus.groovy.syntax.SyntaxException; 76 import org.codehaus.groovy.syntax.Token; 77 import org.codehaus.groovy.syntax.TokenStream; 78 import org.codehaus.groovy.syntax.Types; 79 import org.codehaus.groovy.syntax.lexer.GroovyLexer; 80 import org.codehaus.groovy.syntax.lexer.LexerTokenStream; 81 import org.codehaus.groovy.syntax.lexer.ReaderCharStream; 82 import org.codehaus.groovy.syntax.parser.ASTBuilder; 83 import org.codehaus.groovy.syntax.parser.Parser; 84 import org.codehaus.groovy.syntax.parser.UnexpectedTokenException; 85 import org.codehaus.groovy.tools.Utilities; 86 87 88 89 98 99 public class SourceUnit extends ProcessingUnit 100 { 101 102 105 protected ReaderSource source; protected String name; protected Reduction cst; protected ModuleNode ast; 110 111 112 115 116 public SourceUnit( String name, ReaderSource source, CompilerConfiguration flags, ClassLoader loader ) 117 { 118 super( flags, loader ); 119 120 this.name = name; 121 this.source = source; 122 } 123 124 125 126 129 130 public SourceUnit( File source, CompilerConfiguration configuration, ClassLoader loader ) 131 { 132 this( source.getPath(), new FileReaderSource(source, configuration), configuration, loader ); 133 } 134 135 136 139 140 public SourceUnit( URL source, CompilerConfiguration configuration, ClassLoader loader ) 141 { 142 this( source.getPath(), new URLReaderSource(source, configuration), configuration, loader ); 143 } 144 145 146 147 150 151 public SourceUnit( String name, String source, CompilerConfiguration configuration, ClassLoader loader ) 152 { 153 this( name, new StringReaderSource(source, configuration), configuration, loader ); 154 } 155 156 157 160 161 public String getName() 162 { 163 return name; 164 } 165 166 167 168 171 172 public Reduction getCST() 173 { 174 return this.cst; 175 } 176 177 178 179 183 184 public ModuleNode getAST() 185 { 186 return this.ast; 187 } 188 189 190 191 195 196 public boolean failedWithUnexpectedEOF() 197 { 198 boolean result = false; 199 200 if( this.errors != null ) 201 { 202 Message last = (Message)errors.get(errors.size() - 1); 203 if( last instanceof SyntaxErrorMessage ) 204 { 205 SyntaxException cause = ((SyntaxErrorMessage)last).getCause(); 206 if( cause instanceof UnexpectedTokenException ) 207 { 208 Token unexpected = ((UnexpectedTokenException)cause).getUnexpectedToken(); 209 if( unexpected.isA(Types.EOF) ) 210 { 211 result = true; 212 } 213 } 214 } 215 } 216 217 return result; 218 } 219 220 221 222 225 226 230 231 public static SourceUnit create( String name, String source ) 232 { 233 CompilerConfiguration configuration = new CompilerConfiguration(); 234 configuration.setTolerance( 1 ); 235 236 return new SourceUnit( name, source, configuration, null ); 237 } 238 239 240 241 245 246 public static SourceUnit create( String name, String source, int tolerance ) 247 { 248 CompilerConfiguration configuration = new CompilerConfiguration(); 249 configuration.setTolerance( tolerance ); 250 251 return new SourceUnit( name, source, configuration, null ); 252 } 253 254 255 256 257 258 261 262 265 266 public void parse() throws CompilationFailedException 267 { 268 if( this.phase > Phases.PARSING ) 269 { 270 throw new GroovyBugError( "parsing is already complete" ); 271 } 272 273 if( this.phase == Phases.INITIALIZATION ) 274 { 275 nextPhase(); 276 } 277 278 279 282 Reader reader = null; 283 try 284 { 285 reader = source.getReader(); 286 287 290 GroovyLexer lexer = new GroovyLexer( new ReaderCharStream(reader) ); 291 TokenStream stream = new LexerTokenStream( lexer ); 292 293 296 Parser parser = new Parser( this, stream ); 297 this.cst = parser.parse(); 298 299 completePhase(); 300 } 301 catch( IOException e ) 302 { 303 addFatalError( new SimpleMessage(e.getMessage()) ); 304 } 305 finally 306 { 307 if( reader != null ) 308 { 309 try { reader.close(); } catch( IOException e ) {} 310 } 311 } 312 } 313 314 315 316 319 320 public void convert() throws CompilationFailedException 321 { 322 if( this.phase == Phases.PARSING && this.phaseComplete ) 323 { 324 gotoPhase( Phases.CONVERSION ); 325 } 326 327 if( this.phase != Phases.CONVERSION ) 328 { 329 throw new GroovyBugError( "SourceUnit not ready for convert()" ); 330 } 331 332 333 336 try 337 { 338 ASTBuilder builder = new ASTBuilder( this, this.classLoader ); 339 this.ast = builder.build( this.cst ); 340 this.ast.setDescription( this.name ); 341 } 342 catch( SyntaxException e ) 343 { 344 addError( new SyntaxErrorMessage(e) ); 345 } 346 347 completePhase(); 348 } 349 350 351 352 353 356 357 361 362 public void addWarning( int importance, String text, CSTNode context ) 363 { 364 if( WarningMessage.isRelevant(importance, this.warningLevel) ) 365 { 366 addWarning( new WarningMessage(importance, text, context) ); 367 } 368 } 369 370 371 372 376 377 public void addWarning( int importance, String text, Object data, CSTNode context ) 378 { 379 if( WarningMessage.isRelevant(importance, this.warningLevel) ) 380 { 381 addWarning( new WarningMessage(importance, text, data, context) ); 382 } 383 } 384 385 386 387 390 391 public void addError( SyntaxException error ) throws CompilationFailedException 392 { 393 addError( Message.create(error), error.isFatal() ); 394 } 395 396 397 398 401 402 public void addError( String text, CSTNode context ) throws CompilationFailedException 403 { 404 addError( new LocatedMessage(text, context) ); 405 } 406 407 408 409 410 413 414 418 419 public String getSample( int line, int column, Janitor janitor ) 420 { 421 String sample = null; 422 String text = source.getLine( line, janitor ); 423 424 if( text != null ) 425 { 426 if( column > 0 ) 427 { 428 String marker = Utilities.repeatString(" ", column-1) + "^"; 429 430 if( column > 40 ) 431 { 432 int start = column - 30 - 1; 433 int end = (column + 10 > text.length() ? text.length() : column + 10 - 1); 434 sample = " " + text.substring( start, end ) + Utilities.eol() + " " + marker.substring( start, marker.length() ); 435 } 436 else 437 { 438 sample = " " + text + Utilities.eol() + " " + marker; 439 } 440 } 441 else 442 { 443 sample = text; 444 } 445 } 446 447 return sample; 448 } 449 450 456 public static ModuleNode createModule(String code) throws CompilationFailedException { 457 SourceUnit su = create("NodeGen", code); 458 su.parse(); 459 su.convert(); 460 return su.getAST(); 461 } 462 463 public static ClassNode createClassNode(String code) throws CompilationFailedException { 464 ModuleNode module = createModule(code); 465 List classes = module.getClasses(); 466 if (classes.size() > 1) { 467 throw new RuntimeException ("The code defines more than one class"); 468 } 469 return (ClassNode) classes.get(0); 470 } 471 472 479 public static FieldNode createFieldNode(String code) throws CompilationFailedException { 480 ClassNode classNode = createClassNode(wrapCode(code)); 481 List flds = classNode.getFields(); 482 if (flds.size() > 1) 483 throw new RuntimeException ("The code defines more than one field"); 484 return (FieldNode) flds.get(0); 485 } 486 487 public Statement createStatement(String code) throws CompilationFailedException { 488 ModuleNode module = createModule(code); 489 BlockStatement block = module.getStatementBlock(); 490 if (block == null) 491 throw new RuntimeException ("no proper statement block is created."); 492 List stats = block.getStatements(); 493 if (stats == null || stats.size() != 1) 494 throw new RuntimeException ("no proper statement node is created."); 495 return (Statement)stats.get(0); 496 } 497 498 public MethodNode createMethodNode(String code) throws CompilationFailedException { 499 code = code.trim(); 500 if (code.indexOf("def") != 0) { 501 code = "def " + code; 502 } 503 ModuleNode module = createModule(code); 504 List ms = module.getMethods(); 505 if (ms == null || ms.size() != 1) 506 throw new RuntimeException ("no proper method node is created."); 507 return (MethodNode)ms.get(0); 508 } 509 510 private static String wrapCode(String code) { 511 String prefix = "class SynthedClass {\n"; 512 String suffix = "\n }"; 513 return prefix + code + suffix; 514 515 } 516 } 517 518 519 520 521 | Popular Tags |