Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 521   Methods: 23
NCLOC: 257   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
SourceUnit.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: SourceUnit.java,v 1.2 2004/07/10 03:31:41 bran Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 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   
 /**
 90   
  *  Provides an anchor for a single source unit (usually a script file)
 91   
  *  as it passes through the compiler system.
 92   
  *
 93   
  *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
 94   
  *  @author <a href="mailto:b55r@sina.com">Bing Ran</a>
 95   
  *
 96   
  *  @version $Id: SourceUnit.java,v 1.2 2004/07/10 03:31:41 bran Exp $
 97   
  */
 98   
 
 99   
 public class SourceUnit extends ProcessingUnit
 100   
 {
 101   
     
 102   
   //---------------------------------------------------------------------------
 103   
   // CONSTRUCTION AND SUCH
 104   
     
 105   
     protected ReaderSource source;    // Where we can get Readers for our source unit
 106   
     protected String       name;      // A descriptive name of the source unit
 107   
     protected Reduction    cst;       // A Concrete Syntax Tree of the source
 108   
     protected ModuleNode   ast;       // The root of the Abstract Syntax Tree for the source
 109   
     
 110   
 
 111   
     
 112   
    /**
 113   
     *  Initializes the SourceUnit from existing machinery.
 114   
     */
 115   
     
 116  0
     public SourceUnit( String name, ReaderSource source, CompilerConfiguration flags, ClassLoader loader ) 
 117   
     {
 118  0
         super( flags, loader );
 119   
         
 120  0
         this.name   = name;
 121  0
         this.source = source;
 122   
     }
 123   
     
 124   
     
 125   
 
 126   
    /**
 127   
     *  Initializes the SourceUnit from the specified file.
 128   
     */
 129   
     
 130  0
     public SourceUnit( File source, CompilerConfiguration configuration, ClassLoader loader )
 131   
     {
 132  0
         this( source.getPath(), new FileReaderSource(source, configuration), configuration, loader );
 133   
     }
 134   
     
 135   
 
 136   
    /**
 137   
     *  Initializes the SourceUnit from the specified URL.
 138   
     */
 139   
     
 140  0
     public SourceUnit( URL source, CompilerConfiguration configuration, ClassLoader loader )
 141   
     {
 142  0
         this( source.getPath(), new URLReaderSource(source, configuration), configuration, loader );
 143   
     }
 144   
     
 145   
     
 146   
    
 147   
    /**
 148   
     *  Initializes the SourceUnit for a string of source.
 149   
     */
 150   
     
 151  0
     public SourceUnit( String name, String source, CompilerConfiguration configuration, ClassLoader loader )
 152   
     {
 153  0
         this( name, new StringReaderSource(source, configuration), configuration, loader );
 154   
     }
 155   
     
 156   
     
 157   
    /**
 158   
     *  Returns the name for the SourceUnit.
 159   
     */
 160   
     
 161  0
     public String getName()
 162   
     {
 163  0
         return name;
 164   
     }
 165   
     
 166   
     
 167   
     
 168   
    /**
 169   
     *  Returns the Concrete Syntax Tree produced during parse()ing.
 170   
     */
 171   
     
 172  0
     public Reduction getCST()
 173   
     {
 174  0
         return this.cst;
 175   
     }
 176   
     
 177   
     
 178   
     
 179   
    /**
 180   
     *  Returns the Abstract Syntax Tree produced during parse()ing
 181   
     *  and expanded during later phases.
 182   
     */
 183   
     
 184  0
     public ModuleNode getAST()
 185   
     {
 186  0
         return this.ast;
 187   
     }
 188   
     
 189   
     
 190   
     
 191   
    /**
 192   
     *  Convenience routine, primarily for use by the InteractiveShell,
 193   
     *  that returns true if parse() failed with an unexpected EOF.
 194   
     */
 195   
     
 196  0
     public boolean failedWithUnexpectedEOF()
 197   
     {
 198  0
         boolean result = false;
 199   
         
 200  0
         if( this.errors != null )
 201   
         {
 202  0
             Message last = (Message)errors.get(errors.size() - 1);
 203  0
             if( last instanceof SyntaxErrorMessage ) 
 204   
             {
 205  0
                 SyntaxException cause = ((SyntaxErrorMessage)last).getCause();
 206  0
                 if( cause instanceof UnexpectedTokenException ) 
 207   
                 {
 208  0
                     Token unexpected = ((UnexpectedTokenException)cause).getUnexpectedToken();
 209  0
                     if( unexpected.isA(Types.EOF) )
 210   
                     {
 211  0
                         result = true;
 212   
                     }
 213   
                 }
 214   
             }
 215   
         }
 216   
         
 217  0
         return result;
 218   
     }
 219   
 
 220   
 
 221   
     
 222   
   //---------------------------------------------------------------------------
 223   
   // FACTORIES
 224   
 
 225   
     
 226   
    /**
 227   
     *  A convenience routine to create a standalone SourceUnit on a String 
 228   
     *  with defaults for almost everything that is configurable. 
 229   
     */
 230   
     
 231  0
     public static SourceUnit create( String name, String source )
 232   
     {
 233  0
         CompilerConfiguration configuration = new CompilerConfiguration();
 234  0
         configuration.setTolerance( 1 );
 235   
         
 236  0
         return new SourceUnit( name, source, configuration, null );
 237   
     }
 238   
     
 239   
 
 240   
     
 241   
    /**
 242   
     *  A convenience routine to create a standalone SourceUnit on a String 
 243   
     *  with defaults for almost everything that is configurable. 
 244   
     */
 245   
      
 246  0
     public static SourceUnit create( String name, String source, int tolerance )
 247   
     {
 248  0
         CompilerConfiguration configuration = new CompilerConfiguration();
 249  0
         configuration.setTolerance( tolerance );
 250   
         
 251  0
         return new SourceUnit( name, source, configuration, null );
 252   
     }
 253   
      
 254   
 
 255   
      
 256   
      
 257   
     
 258   
   //---------------------------------------------------------------------------
 259   
   // PROCESSING
 260   
 
 261   
     
 262   
    /**
 263   
     *  Parses the source to a CST.  You can retrieve it with getCST().
 264   
     */
 265   
     
 266  0
     public void parse() throws CompilationFailedException
 267   
     {
 268  0
         if( this.phase > Phases.PARSING )
 269   
         {
 270  0
             throw new GroovyBugError( "parsing is already complete" );
 271   
         }
 272   
         
 273  0
         if( this.phase == Phases.INITIALIZATION )
 274   
         {
 275  0
             nextPhase();
 276   
         }
 277   
     
 278   
         
 279   
         //
 280   
         // Create a reader on the source and run the parser.
 281   
         
 282  0
         Reader reader = null;
 283  0
         try
 284   
         {
 285  0
             reader = source.getReader();
 286   
 
 287   
             //
 288   
             // Create a lexer and token stream
 289   
 
 290  0
             GroovyLexer lexer  = new GroovyLexer( new ReaderCharStream(reader) );
 291  0
             TokenStream stream = new LexerTokenStream( lexer );
 292   
             
 293   
             //
 294   
             // Do the parsing
 295   
             
 296  0
             Parser parser = new Parser( this, stream );
 297  0
             this.cst = parser.parse();
 298   
             
 299  0
             completePhase();
 300   
         }
 301   
         catch( IOException e )
 302   
         {
 303  0
             addFatalError( new SimpleMessage(e.getMessage()) );
 304   
         }
 305   
         finally
 306   
         {
 307  0
             if( reader != null )
 308   
             {
 309  0
                 try { reader.close(); } catch( IOException e ) {}
 310   
             }
 311   
         }
 312   
     }
 313   
     
 314   
     
 315   
     
 316   
    /**
 317   
     *  Generates an AST from the CST.  You can retrieve it with getAST().
 318   
     */
 319   
 
 320  0
     public void convert() throws CompilationFailedException
 321   
     {
 322  0
         if( this.phase == Phases.PARSING && this.phaseComplete )
 323   
         {
 324  0
             gotoPhase( Phases.CONVERSION );
 325   
         }
 326   
         
 327  0
         if( this.phase != Phases.CONVERSION )
 328   
         {
 329  0
             throw new GroovyBugError( "SourceUnit not ready for convert()" );
 330   
         }
 331   
 
 332   
         
 333   
         //
 334   
         // Build the AST
 335   
         
 336  0
         try
 337   
         {
 338  0
             ASTBuilder builder = new ASTBuilder( this, this.classLoader );
 339  0
             this.ast = builder.build( this.cst );
 340  0
             this.ast.setDescription( this.name );
 341   
         }
 342   
         catch( SyntaxException e )
 343   
         {
 344  0
             addError( new SyntaxErrorMessage(e) );
 345   
         }
 346   
         
 347  0
         completePhase();
 348   
     }
 349   
     
 350   
     
 351   
 
 352   
     
 353   
   //---------------------------------------------------------------------------
 354   
   // ERROR REPORTING
 355   
 
 356   
     
 357   
    /**
 358   
     *  Convenience wrapper for addWarning() that won't create an object
 359   
     *  unless it is relevant.
 360   
     */
 361   
      
 362  0
     public void addWarning( int importance, String text, CSTNode context )
 363   
     {
 364  0
         if( WarningMessage.isRelevant(importance, this.warningLevel) )
 365   
         {
 366  0
             addWarning( new WarningMessage(importance, text, context) );
 367   
         }
 368   
     }
 369   
      
 370   
     
 371   
     
 372   
     /**
 373   
      *  Convenience wrapper for addWarning() that won't create an object
 374   
      *  unless it is relevant.
 375   
      */
 376   
       
 377  0
     public void addWarning( int importance, String text, Object data, CSTNode context )
 378   
     {
 379  0
         if( WarningMessage.isRelevant(importance, this.warningLevel) )
 380   
         {
 381  0
             addWarning( new WarningMessage(importance, text, data, context) );
 382   
         }
 383   
     }
 384   
 
 385   
      
 386   
      
 387   
    /**
 388   
     *  Convenience wrapper for addError().
 389   
     */
 390   
     
 391  0
     public void addError( SyntaxException error ) throws CompilationFailedException
 392   
     {
 393  0
         addError( Message.create(error), error.isFatal() );
 394   
     }
 395   
     
 396   
     
 397   
     
 398   
    /**
 399   
     *  Convenience wrapper for addError().
 400   
     */
 401   
     
 402  0
     public void addError( String text, CSTNode context ) throws CompilationFailedException
 403   
     {
 404  0
         addError( new LocatedMessage(text, context) );
 405   
     }
 406   
 
 407   
     
 408   
     
 409   
     
 410   
   //---------------------------------------------------------------------------
 411   
   // SOURCE SAMPLING
 412   
 
 413   
     
 414   
    /**
 415   
     *  Returns a sampling of the source at the specified line and column,
 416   
     *  of null if it is unavailable.
 417   
     */
 418   
     
 419  0
     public String getSample( int line, int column, Janitor janitor )
 420   
     {
 421  0
         String sample = null;
 422  0
         String text   = source.getLine( line, janitor );
 423   
 
 424  0
         if( text != null )
 425   
         {
 426  0
             if( column > 0 )
 427   
             {
 428  0
                 String marker = Utilities.repeatString(" ", column-1) + "^";
 429   
 
 430  0
                 if( column > 40 )
 431   
                 {
 432  0
                     int start = column - 30 - 1;
 433  0
                     int end   = (column + 10 > text.length() ? text.length() : column + 10 - 1);
 434  0
                     sample = "   " + text.substring( start, end ) + Utilities.eol() + "   " + marker.substring( start, marker.length() );
 435   
                 }
 436   
                 else
 437   
                 {
 438  0
                     sample = "   " + text + Utilities.eol() + "   " + marker;
 439   
                 }
 440   
             }
 441   
             else
 442   
             {
 443  0
                 sample = text;
 444   
             }
 445   
         }
 446   
 
 447  0
         return sample;
 448   
     }
 449   
     
 450   
     /**
 451   
      * to quickly create a ModuleNode from a piece of Groovy code
 452   
      * @param code
 453   
      * @return
 454   
      * @throws CompilationFailedException
 455   
      */
 456  0
     public static ModuleNode createModule(String code) throws CompilationFailedException {
 457  0
         SourceUnit su = create("NodeGen", code);
 458  0
         su.parse();
 459  0
         su.convert();
 460  0
         return su.getAST();
 461   
     }
 462   
     
 463  0
     public static ClassNode createClassNode(String code) throws CompilationFailedException {
 464  0
         ModuleNode module = createModule(code);
 465  0
         List classes = module.getClasses();
 466  0
         if (classes.size() > 1) {
 467  0
             throw new RuntimeException("The code defines more than one class");
 468   
         }
 469  0
         return (ClassNode) classes.get(0);
 470   
     }
 471   
 
 472   
     /**
 473   
      * Takes a field definition statement and wrap it in class definition. The FieldNode object
 474   
      * representing the field is extracted and returned, Types need to be fully qualified. 
 475   
      * @param code a naked statement to define a field, such as: String prop = "hello"
 476   
      * @return a FieldNode object. 
 477   
      * @throws CompilationFailedException
 478   
      */
 479  0
     public static FieldNode createFieldNode(String code) throws CompilationFailedException {
 480  0
         ClassNode classNode = createClassNode(wrapCode(code));
 481  0
         List flds = classNode.getFields();
 482  0
         if (flds.size() > 1) 
 483  0
             throw new RuntimeException("The code defines more than one field");            
 484  0
         return (FieldNode) flds.get(0);
 485   
     }
 486   
     
 487  0
     public Statement createStatement(String code) throws CompilationFailedException {
 488  0
         ModuleNode module = createModule(code);
 489  0
         BlockStatement block = module.getStatementBlock();
 490  0
         if (block == null)
 491  0
             throw new RuntimeException("no proper statement block is created.");
 492  0
         List stats = block.getStatements();
 493  0
         if (stats == null || stats.size() != 1)
 494  0
             throw new RuntimeException("no proper statement node is created.");
 495  0
         return (Statement)stats.get(0);
 496   
     }
 497   
     
 498  0
     public MethodNode createMethodNode(String code) throws CompilationFailedException {
 499  0
         code  = code.trim();
 500  0
         if (code.indexOf("def") != 0) {
 501  0
             code = "def " + code;
 502   
         }
 503  0
         ModuleNode module = createModule(code);
 504  0
         List ms = module.getMethods();
 505  0
         if (ms == null || ms.size() != 1)
 506  0
             throw new RuntimeException("no proper method node is created.");
 507  0
         return (MethodNode)ms.get(0);
 508   
     }
 509   
     
 510  0
     private static String wrapCode(String code) {
 511  0
         String prefix = "class SynthedClass {\n";
 512  0
         String suffix = "\n }";
 513  0
         return prefix + code + suffix;
 514   
             
 515   
     }
 516   
 }
 517   
 
 518   
 
 519   
 
 520   
 
 521