Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 510   Methods: 14
NCLOC: 224   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
InteractiveShell.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: InteractiveShell.java,v 1.12 2004/04/19 07:29:43 cpoirier 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   
 package groovy.ui;
 47   
 
 48   
 import groovy.lang.GroovyShell;
 49   
 
 50   
 import java.io.BufferedReader;
 51   
 import java.io.IOException;
 52   
 import java.io.InputStreamReader;
 53   
 import java.util.HashMap;
 54   
 import java.util.Map;
 55   
 
 56   
 import org.codehaus.groovy.control.CompilationFailedException;
 57   
 import org.codehaus.groovy.control.SourceUnit;
 58   
 import org.codehaus.groovy.runtime.InvokerHelper;
 59   
 import org.codehaus.groovy.syntax.CSTNode;
 60   
 import org.codehaus.groovy.syntax.TokenStream;
 61   
 import org.codehaus.groovy.tools.ErrorReporter;
 62   
 
 63   
 
 64   
 /**
 65   
  *  A simple interactive shell for evaluating groovy expressions
 66   
  *  on the command line
 67   
  * 
 68   
  *  @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 69   
  *  @author <a href="mailto:cpoirier@dreaming.org"   >Chris Poirier</a>
 70   
  *  @version $Revision: 1.12 $
 71   
  */
 72   
 public class InteractiveShell {
 73   
 
 74   
     GroovyShell shell = new GroovyShell();
 75   
     BufferedReader reader;
 76   
 
 77   
 
 78   
    /**
 79   
     *  Entry point when called directly.
 80   
     */
 81   
 
 82  0
     public static void main(String args[]) {
 83  0
         try {
 84  0
             InteractiveShell groovy = new InteractiveShell();
 85  0
             groovy.run(args);
 86   
         }
 87   
         catch (Exception e) {
 88  0
             System.out.println("Caught: " + e);
 89  0
             e.printStackTrace();
 90   
         }
 91   
     }
 92   
 
 93   
 
 94   
    /**
 95   
     *  Default constructor.
 96   
     */
 97   
 
 98  0
     public InteractiveShell() {
 99   
     }
 100   
 
 101   
 
 102   
 
 103   
   //---------------------------------------------------------------------------
 104   
   // COMMAND LINE PROCESSING LOOP
 105   
 
 106   
 
 107   
    /**
 108   
     *  Reads commands and statements from input stream and processes them.
 109   
     */
 110   
 
 111  0
     public void run(String[] args) throws Exception {
 112  0
         reader = new BufferedReader(new InputStreamReader(System.in));
 113   
 
 114  0
         String version = InvokerHelper.getVersion();
 115   
         
 116  0
         System.out.println("Lets get Groovy!");
 117  0
         System.out.println("================");
 118  0
         System.out.println("Version: " + version + " JVM: " + System.getProperty("java.vm.version"));
 119  0
         System.out.println("Type 'exit' to terminate the shell");
 120  0
         System.out.println("Type 'help' for command help");
 121   
         
 122  0
         int counter = 1;
 123  0
         while( true ) {
 124   
             
 125   
             //
 126   
             // Read a single top-level statement from the command line, 
 127   
             // trapping errors as they happen.  We quit on null.
 128   
 
 129  0
             String command = read();
 130  0
             if( command == null ) {
 131  0
                 break;
 132   
             }
 133   
 
 134  0
             reset();
 135   
 
 136  0
             if( command.length() > 0 ) {
 137   
               
 138   
                 //
 139   
                 // We have a command that parses, so evaluate it.
 140   
 
 141  0
                 try {
 142  0
                     Object answer = shell.evaluate(command, "CommandLine" + counter++ +".groovy");
 143   
                     // System.out.println(InvokerHelper.inspect(answer));
 144   
                 }
 145   
                 catch( Exception e ) {
 146  0
                     new ErrorReporter( e, false ).write( System.err );
 147   
                 }
 148   
                 catch( Throwable e ) {
 149  0
                     new ErrorReporter( e, false ).write( System.err );
 150  0
                     System.err.println( ">>> exiting" );
 151  0
                     System.exit(1);
 152   
                 }
 153   
             }
 154   
         }
 155   
     }
 156   
 
 157   
 
 158   
 
 159   
 
 160   
   //---------------------------------------------------------------------------
 161   
   // COMMAND LINE PROCESSING MACHINERY
 162   
 
 163   
 
 164   
     private StringBuffer accepted = new StringBuffer();  // The statement text accepted to date
 165   
     private String       pending  = null;                // A line of statement text not yet accepted
 166   
     private int          line     = 1;                   // The current line number
 167   
 
 168   
     private boolean      stale    = false;               // Set to force clear of accepted
 169   
 
 170   
     private SourceUnit   parser   = null;                // A SourceUnit used to check the statement
 171   
     private TokenStream  stream   = null;                // The TokenStream that backs the Parser
 172   
     private Exception    error    = null;                // Any actual syntax error caught during parsing
 173   
     private CSTNode      tree     = null;                // The top-level statement when parsed
 174   
 
 175   
         
 176   
 
 177   
    /** 
 178   
     *  Resets the command-line processing machinery after use.
 179   
     */
 180   
 
 181  0
     protected void reset() {
 182  0
         stale   = true;
 183  0
         pending = null;
 184  0
         line    = 1;
 185   
 
 186  0
         parser  = null;
 187  0
         stream  = null;
 188  0
         error   = null;
 189  0
         tree    = null;
 190   
     }
 191   
 
 192   
 
 193   
 
 194   
    /**
 195   
     *  Reads a single statement from the command line.  Also identifies
 196   
     *  and processes command shell commands.  Returns the command text
 197   
     *  on success, or null when command processing is complete.
 198   
     *  <p>
 199   
     *  NOTE: Changed, for now, to read until 'execute' is issued.  At
 200   
     *  'execute', the statement must be complete.
 201   
     */
 202   
 
 203  0
     protected String read() {
 204   
 
 205  0
         reset();
 206  0
         System.out.println( "" );
 207   
 
 208  0
         boolean complete = false;
 209  0
         boolean done     = false;
 210   
 
 211  0
         while( /* !complete && */ !done ) {
 212   
 
 213   
             //
 214   
             // Prompt
 215   
 
 216  0
             System.out.print( line + "> ");
 217   
 
 218   
 
 219   
             //
 220   
             // Read a line.  If IOException or null, or command "exit", terminate
 221   
             // processing.  
 222   
 
 223  0
             try { pending = reader.readLine(); } catch( IOException e ) { }
 224   
 
 225  0
             if( pending == null || (COMMAND_MAPPINGS.containsKey(pending) && ((Integer)COMMAND_MAPPINGS.get(pending)).intValue() == COMMAND_ID_EXIT) ) {
 226  0
                 return null;                                  // <<<< FLOW CONTROL <<<<<<<<
 227   
             }
 228   
 
 229   
 
 230   
             //
 231   
             // First up, try to process the line as a command and proceed accordingly.
 232   
 
 233  0
             if( COMMAND_MAPPINGS.containsKey(pending) ) {
 234   
 
 235  0
                 int code = ((Integer)COMMAND_MAPPINGS.get(pending)).intValue();
 236  0
                 switch( code ) {
 237   
 
 238   
                   case COMMAND_ID_HELP:
 239  0
                     displayHelp();
 240  0
                     break;
 241   
 
 242   
                   case COMMAND_ID_DISCARD:
 243  0
                     reset();
 244  0
                     done = true;
 245  0
                     break;
 246   
 
 247   
                   case COMMAND_ID_DISPLAY:
 248  0
                     displayStatement();
 249  0
                     break;
 250   
 
 251   
                   case COMMAND_ID_EXPLAIN:
 252  0
                     explainStatement();
 253  0
                     break;
 254   
 
 255   
                   case COMMAND_ID_EXECUTE:
 256  0
                     if( complete ) {
 257  0
                         done = true;
 258   
                     }
 259   
                     else {
 260  0
                         System.err.println( "statement not complete" );
 261   
                     }
 262  0
                     break;
 263   
                 }
 264   
 
 265  0
                 continue;                                     // <<<< LOOP CONTROL <<<<<<<<
 266   
 
 267   
             }
 268   
 
 269   
 
 270   
             //
 271   
             // Otherwise, it's part of a statement.  If it's just whitespace,
 272   
             // we'll just accept it and move on.  Otherwise, parsing is attempted
 273   
             // on the cumulated statement text, and errors are reported.  The
 274   
             // pending input is accepted or rejected based on that parsing.
 275   
 
 276  0
             freshen();
 277   
 
 278  0
             if( pending.trim() == "" ) {
 279  0
                 accept();
 280  0
                 continue;                                     // <<<< LOOP CONTROL <<<<<<<<
 281   
             }
 282   
 
 283  0
             String code = current();
 284   
 
 285  0
             if( parse(code, 1) ) {
 286  0
                 accept();
 287  0
                 complete = true;
 288   
             }
 289  0
             else if( error == null ) {
 290  0
                 accept();
 291   
             }
 292   
             else {
 293  0
                 report( );
 294   
             }
 295   
 
 296   
         }
 297   
 
 298   
 
 299   
         //
 300   
         // Get and return the statement.
 301   
 
 302  0
         return accepted( complete );
 303   
     }
 304   
 
 305   
 
 306   
        
 307   
    /**
 308   
     *  Returns the accepted statement as a string.  If not <code>complete</code>,
 309   
     *  returns the empty string.
 310   
     */
 311   
 
 312  0
     private String accepted( boolean complete ) {
 313  0
         if( complete ) {
 314  0
             return accepted.toString();
 315   
         }
 316  0
         return ""; 
 317   
     }
 318   
 
 319   
 
 320   
 
 321   
    /**
 322   
     *  Returns the current statement, including pending text.
 323   
     */
 324   
 
 325  0
     private String current( ) {
 326  0
         return accepted.toString() + pending + "\n";
 327   
     }
 328   
 
 329   
 
 330   
 
 331   
    /**
 332   
     *  Accepts the pending text into the statement.
 333   
     */
 334   
 
 335  0
     private void accept() {
 336  0
         accepted.append( pending ).append( "\n" );
 337  0
         line += 1;
 338   
     }
 339   
 
 340   
 
 341   
    /**
 342   
     *  Clears accepted if stale.
 343   
     */
 344   
 
 345  0
     private void freshen() {
 346  0
         if( stale ) {
 347  0
             accepted.setLength(0);
 348  0
             stale = false;
 349   
         }
 350   
     }
 351   
 
 352   
 
 353   
 
 354   
 
 355   
 
 356   
   //---------------------------------------------------------------------------
 357   
   // SUPPORT ROUTINES
 358   
 
 359   
 
 360   
    /**
 361   
     *  Attempts to parse the specified code with the specified tolerance.
 362   
     *  Updates the <code>parser</code> and <code>error</code> members 
 363   
     *  appropriately.  Returns true if the text parsed, false otherwise.
 364   
     *  The attempts to identify and suppress errors resulting from the
 365   
     *  unfinished source text.
 366   
     */
 367   
 
 368  0
     private boolean parse( String code, int tolerance ) {
 369   
 
 370  0
         boolean parsed = false;
 371   
 
 372  0
         parser = null;
 373  0
         stream = null;
 374  0
         error  = null;
 375  0
         tree   = null;
 376   
 
 377   
         //
 378   
         // Create the parser and attempt to parse the text as a top-level statement.
 379   
 
 380  0
         try {
 381   
             
 382  0
             parser = SourceUnit.create( "groovysh script", code, tolerance );
 383  0
             parser.parse();
 384  0
             tree = parser.getCST();
 385   
 
 386   
             /* see note on read(): 
 387   
              * tree = parser.topLevelStatement();
 388   
              *
 389   
              * if( stream.atEnd() ) {
 390   
              *     parsed = true;
 391   
              * }
 392   
              */
 393   
             
 394  0
             parsed = true;
 395   
         }
 396   
 
 397   
         //
 398   
         // We report errors other than unexpected EOF to the user.
 399   
 
 400   
         catch( CompilationFailedException e ) {
 401  0
             if( parser.getErrorCount() > 1 || !parser.failedWithUnexpectedEOF() ) {
 402  0
                 error = e;
 403   
             }
 404   
         }
 405   
 
 406   
         catch( Exception e ) {
 407  0
             error = e;
 408   
         }
 409   
 
 410  0
         return parsed;
 411   
     }
 412   
 
 413   
 
 414   
 
 415   
    /** 
 416   
     *  Reports the last parsing error to the user.
 417   
     */
 418   
 
 419  0
     private void report() {
 420  0
         System.err.println( "discarding invalid text:" );
 421  0
         new ErrorReporter( error, false ).write( System.err );
 422   
     }
 423   
 
 424   
 
 425   
 
 426   
 
 427   
 
 428   
   //-----------------------------------------------------------------------
 429   
   // COMMANDS
 430   
 
 431   
     private static final int COMMAND_ID_EXIT    = 0;
 432   
     private static final int COMMAND_ID_HELP    = 1;
 433   
     private static final int COMMAND_ID_DISCARD = 2;
 434   
     private static final int COMMAND_ID_DISPLAY = 3;
 435   
     private static final int COMMAND_ID_EXPLAIN = 4;
 436   
     private static final int COMMAND_ID_EXECUTE = 5;
 437   
     private static final int LAST_COMMAND_ID    = 5;
 438   
 
 439   
     private static final String[] COMMANDS = { "exit", "help", "discard", "display", "explain", "execute" };
 440   
 
 441   
     private static final Map COMMAND_MAPPINGS = new HashMap();
 442   
 
 443   
     static {
 444  0
         for( int i = 0; i <= LAST_COMMAND_ID; i++ ) {
 445  0
             COMMAND_MAPPINGS.put( COMMANDS[i], new Integer(i) );
 446   
         }
 447   
 
 448   
         // A few synonyms
 449   
 
 450  0
         COMMAND_MAPPINGS.put( "quit", new Integer(COMMAND_ID_EXIT) );
 451  0
         COMMAND_MAPPINGS.put( "go"  , new Integer(COMMAND_ID_EXECUTE) );
 452   
     }
 453   
 
 454   
     private static final Map COMMAND_HELP = new HashMap();
 455   
 
 456   
     static {
 457  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXIT   ], "exit/quit  - terminates processing"          );
 458  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_HELP   ], "help       - displays this help text"        );
 459  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_DISCARD], "discard    - discards the current statement" );
 460  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_DISPLAY], "display    - displays the current statement" );
 461  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXPLAIN], "explain    - explains the parsing of the current statement" );
 462  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXECUTE], "execute/go - temporary command to cause statement execution" );
 463   
     }
 464   
 
 465   
 
 466   
 
 467   
    /**
 468   
     *  Displays help text about available commands.
 469   
     */
 470   
 
 471  0
     private void displayHelp() {
 472  0
         System.out.println( "Available commands (must be entered without extraneous characters):" );
 473  0
         for( int i = 0; i <= LAST_COMMAND_ID; i++ ) {
 474  0
             System.out.println( (String)COMMAND_HELP.get(COMMANDS[i]) );
 475   
         }
 476   
     }
 477   
 
 478   
 
 479   
 
 480   
    /**
 481   
     *  Displays the accepted statement.
 482   
     */
 483   
 
 484  0
     private void displayStatement() {
 485  0
         String[] lines = accepted.toString().split("\n");
 486  0
         for( int i = 0; i < lines.length; i++ ) {
 487  0
             System.out.println( (i+1) + "> " + lines[i] );
 488   
         }
 489   
     }
 490   
 
 491   
 
 492   
 
 493   
    /**
 494   
     *  Attempts to parse the accepted statement and display the 
 495   
     *  parse tree for it.
 496   
     */
 497   
 
 498  0
     private void explainStatement() {
 499   
 
 500  0
         if( parse(accepted(true), 10) || error == null ) {
 501  0
             System.out.println( "parse tree:" );
 502  0
             System.out.println( tree );
 503   
         }
 504   
         else {
 505  0
             System.out.println( "statement does not parse" );
 506   
         }
 507   
     }
 508   
 }
 509   
 
 510