Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 507   Methods: 15
NCLOC: 228   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.14 2004/09/28 20:08:34 yuri 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.IOException;
 51   
 import java.util.HashMap;
 52   
 import java.util.Map;
 53   
 
 54   
 import org.codehaus.groovy.control.CompilationFailedException;
 55   
 import org.codehaus.groovy.control.SourceUnit;
 56   
 import org.codehaus.groovy.runtime.InvokerHelper;
 57   
 import org.codehaus.groovy.sandbox.ui.Prompt;
 58   
 import org.codehaus.groovy.sandbox.ui.PromptFactory;
 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   
  *  @author Yuri Schimke
 71   
  *  @version $Revision: 1.14 $
 72   
  */
 73   
 public class InteractiveShell {
 74   
     protected GroovyShell shell = new GroovyShell();
 75   
     protected Prompt prompt;
 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   
    * @throws IOException if there was a problem with the history file.
 97   
     */
 98  0
     public InteractiveShell() throws IOException {
 99  0
       prompt = PromptFactory.buildPrompt();
 100  0
       prompt.setPrompt("groovy> ");
 101   
     }
 102   
 
 103   
 
 104   
 
 105   
   //---------------------------------------------------------------------------
 106   
   // COMMAND LINE PROCESSING LOOP
 107   
 
 108   
 
 109   
    /**
 110   
     *  Reads commands and statements from input stream and processes them.
 111   
     */
 112   
 
 113  0
     public void run(String[] args) throws Exception {
 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
               close();
 132  0
                 break;
 133   
             }
 134   
 
 135  0
             reset();
 136   
 
 137  0
             if( command.length() > 0 ) {
 138   
               
 139   
                 //
 140   
                 // We have a command that parses, so evaluate it.
 141   
 
 142  0
                 try {
 143  0
                     Object answer = shell.evaluate(command, "CommandLine" + counter++ +".groovy");
 144   
                     // System.out.println(InvokerHelper.inspect(answer));
 145   
                 }
 146   
                 catch( Exception e ) {
 147  0
                     new ErrorReporter( e, false ).write( System.err );
 148   
                 }
 149   
                 catch( Throwable e ) {
 150  0
                     new ErrorReporter( e, false ).write( System.err );
 151  0
                     System.err.println( ">>> exiting" );
 152  0
                     System.exit(1);
 153   
                 }
 154   
             }
 155   
         }
 156   
     }
 157   
 
 158   
 
 159  0
     protected void close() {
 160  0
       prompt.close();
 161   
     }
 162   
 
 163   
 
 164   
   //---------------------------------------------------------------------------
 165   
   // COMMAND LINE PROCESSING MACHINERY
 166   
 
 167   
 
 168   
 
 169   
 
 170   
 
 171   
     private StringBuffer accepted = new StringBuffer();  // The statement text accepted to date
 172   
     private String       pending  = null;                // A line of statement text not yet accepted
 173   
     private int          line     = 1;                   // The current line number
 174   
 
 175   
     private boolean      stale    = false;               // Set to force clear of accepted
 176   
 
 177   
     private SourceUnit   parser   = null;                // A SourceUnit used to check the statement
 178   
     private TokenStream  stream   = null;                // The TokenStream that backs the Parser
 179   
     private Exception    error    = null;                // Any actual syntax error caught during parsing
 180   
     private CSTNode      tree     = null;                // The top-level statement when parsed
 181   
 
 182   
         
 183   
 
 184   
    /** 
 185   
     *  Resets the command-line processing machinery after use.
 186   
     */
 187   
 
 188  0
     protected void reset() {
 189  0
         stale   = true;
 190  0
         pending = null;
 191  0
         line    = 1;
 192   
 
 193  0
         parser  = null;
 194  0
         stream  = null;
 195  0
         error   = null;
 196  0
         tree    = null;
 197   
     }
 198   
 
 199   
 
 200   
 
 201   
    /**
 202   
     *  Reads a single statement from the command line.  Also identifies
 203   
     *  and processes command shell commands.  Returns the command text
 204   
     *  on success, or null when command processing is complete.
 205   
     *  <p>
 206   
     *  NOTE: Changed, for now, to read until 'execute' is issued.  At
 207   
     *  'execute', the statement must be complete.
 208   
     */
 209   
 
 210  0
     protected String read() {
 211   
 
 212  0
         reset();
 213  0
         System.out.println( "" );
 214   
 
 215  0
         boolean complete = false;
 216  0
         boolean done     = false;
 217   
 
 218  0
         while( /* !complete && */ !done ) {
 219   
 
 220   
             //
 221   
             // Read a line.  If IOException or null, or command "exit", terminate
 222   
             // processing.  
 223   
 
 224  0
             try { pending = prompt.readLine(); } catch( IOException e ) { }
 225   
 
 226  0
             if( pending == null || (COMMAND_MAPPINGS.containsKey(pending) && ((Integer)COMMAND_MAPPINGS.get(pending)).intValue() == COMMAND_ID_EXIT) ) {
 227  0
                 return null;                                  // <<<< FLOW CONTROL <<<<<<<<
 228   
             }
 229   
 
 230   
 
 231   
             //
 232   
             // First up, try to process the line as a command and proceed accordingly.
 233   
 
 234  0
             if( COMMAND_MAPPINGS.containsKey(pending) ) {
 235   
 
 236  0
                 int code = ((Integer)COMMAND_MAPPINGS.get(pending)).intValue();
 237  0
                 switch( code ) {
 238   
 
 239   
                   case COMMAND_ID_HELP:
 240  0
                     displayHelp();
 241  0
                     break;
 242   
 
 243   
                   case COMMAND_ID_DISCARD:
 244  0
                     reset();
 245  0
                     done = true;
 246  0
                     break;
 247   
 
 248   
                   case COMMAND_ID_DISPLAY:
 249  0
                     displayStatement();
 250  0
                     break;
 251   
 
 252   
                   case COMMAND_ID_EXPLAIN:
 253  0
                     explainStatement();
 254  0
                     break;
 255   
 
 256   
                   case COMMAND_ID_EXECUTE:
 257  0
                     if( complete ) {
 258  0
                         done = true;
 259   
                     }
 260   
                     else {
 261  0
                         System.err.println( "statement not complete" );
 262   
                     }
 263  0
                     break;
 264   
                 }
 265   
 
 266  0
                 continue;                                     // <<<< LOOP CONTROL <<<<<<<<
 267   
 
 268   
             }
 269   
 
 270   
 
 271   
             //
 272   
             // Otherwise, it's part of a statement.  If it's just whitespace,
 273   
             // we'll just accept it and move on.  Otherwise, parsing is attempted
 274   
             // on the cumulated statement text, and errors are reported.  The
 275   
             // pending input is accepted or rejected based on that parsing.
 276   
 
 277  0
             freshen();
 278   
 
 279  0
             if( pending.trim() == "" ) {
 280  0
                 accept();
 281  0
                 continue;                                     // <<<< LOOP CONTROL <<<<<<<<
 282   
             }
 283   
 
 284  0
             String code = current();
 285   
 
 286  0
             if( parse(code, 1) ) {
 287  0
                 accept();
 288  0
                 complete = true;
 289   
             }
 290  0
             else if( error == null ) {
 291  0
                 accept();
 292   
             }
 293   
             else {
 294  0
                 report( );
 295   
             }
 296   
 
 297   
         }
 298   
 
 299   
 
 300   
         //
 301   
         // Get and return the statement.
 302   
 
 303  0
         return accepted( complete );
 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   
   // SUPPORT ROUTINES
 355   
 
 356   
 
 357   
    /**
 358   
     *  Attempts to parse the specified code with the specified tolerance.
 359   
     *  Updates the <code>parser</code> and <code>error</code> members 
 360   
     *  appropriately.  Returns true if the text parsed, false otherwise.
 361   
     *  The attempts to identify and suppress errors resulting from the
 362   
     *  unfinished source text.
 363   
     */
 364   
 
 365  0
     private boolean parse( String code, int tolerance ) {
 366   
 
 367  0
         boolean parsed = false;
 368   
 
 369  0
         parser = null;
 370  0
         stream = null;
 371  0
         error  = null;
 372  0
         tree   = null;
 373   
 
 374   
         //
 375   
         // Create the parser and attempt to parse the text as a top-level statement.
 376   
 
 377  0
         try {
 378   
             
 379  0
             parser = SourceUnit.create( "groovysh script", code, tolerance );
 380  0
             parser.parse();
 381  0
             tree = parser.getCST();
 382   
 
 383   
             /* see note on read(): 
 384   
              * tree = parser.topLevelStatement();
 385   
              *
 386   
              * if( stream.atEnd() ) {
 387   
              *     parsed = true;
 388   
              * }
 389   
              */
 390   
             
 391  0
             parsed = true;
 392   
         }
 393   
 
 394   
         //
 395   
         // We report errors other than unexpected EOF to the user.
 396   
 
 397   
         catch( CompilationFailedException e ) {
 398  0
             if( parser.getErrorCount() > 1 || !parser.failedWithUnexpectedEOF() ) {
 399  0
                 error = e;
 400   
             }
 401   
         }
 402   
 
 403   
         catch( Exception e ) {
 404  0
             error = e;
 405   
         }
 406   
 
 407  0
         return parsed;
 408   
     }
 409   
 
 410   
 
 411   
 
 412   
    /** 
 413   
     *  Reports the last parsing error to the user.
 414   
     */
 415   
 
 416  0
     private void report() {
 417  0
         System.err.println( "discarding invalid text:" );
 418  0
         new ErrorReporter( error, false ).write( System.err );
 419   
     }
 420   
 
 421   
 
 422   
 
 423   
 
 424   
 
 425   
   //-----------------------------------------------------------------------
 426   
   // COMMANDS
 427   
 
 428   
     private static final int COMMAND_ID_EXIT    = 0;
 429   
     private static final int COMMAND_ID_HELP    = 1;
 430   
     private static final int COMMAND_ID_DISCARD = 2;
 431   
     private static final int COMMAND_ID_DISPLAY = 3;
 432   
     private static final int COMMAND_ID_EXPLAIN = 4;
 433   
     private static final int COMMAND_ID_EXECUTE = 5;
 434   
     private static final int LAST_COMMAND_ID    = 5;
 435   
 
 436   
     private static final String[] COMMANDS = { "exit", "help", "discard", "display", "explain", "execute" };
 437   
 
 438   
     private static final Map COMMAND_MAPPINGS = new HashMap();
 439   
 
 440   
     static {
 441  0
         for( int i = 0; i <= LAST_COMMAND_ID; i++ ) {
 442  0
             COMMAND_MAPPINGS.put( COMMANDS[i], new Integer(i) );
 443   
         }
 444   
 
 445   
         // A few synonyms
 446   
 
 447  0
         COMMAND_MAPPINGS.put( "quit", new Integer(COMMAND_ID_EXIT) );
 448  0
         COMMAND_MAPPINGS.put( "go"  , new Integer(COMMAND_ID_EXECUTE) );
 449   
     }
 450   
 
 451   
     private static final Map COMMAND_HELP = new HashMap();
 452   
 
 453   
     static {
 454  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXIT   ], "exit/quit  - terminates processing"          );
 455  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_HELP   ], "help       - displays this help text"        );
 456  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_DISCARD], "discard    - discards the current statement" );
 457  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_DISPLAY], "display    - displays the current statement" );
 458  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXPLAIN], "explain    - explains the parsing of the current statement" );
 459  0
         COMMAND_HELP.put( COMMANDS[COMMAND_ID_EXECUTE], "execute/go - temporary command to cause statement execution" );
 460   
     }
 461   
 
 462   
 
 463   
 
 464   
    /**
 465   
     *  Displays help text about available commands.
 466   
     */
 467   
 
 468  0
     private void displayHelp() {
 469  0
         System.out.println( "Available commands (must be entered without extraneous characters):" );
 470  0
         for( int i = 0; i <= LAST_COMMAND_ID; i++ ) {
 471  0
             System.out.println( (String)COMMAND_HELP.get(COMMANDS[i]) );
 472   
         }
 473   
     }
 474   
 
 475   
 
 476   
 
 477   
    /**
 478   
     *  Displays the accepted statement.
 479   
     */
 480   
 
 481  0
     private void displayStatement() {
 482  0
         String[] lines = accepted.toString().split("\n");
 483  0
         for( int i = 0; i < lines.length; i++ ) {
 484  0
             System.out.println( (i+1) + "> " + lines[i] );
 485   
         }
 486   
     }
 487   
 
 488   
 
 489   
 
 490   
    /**
 491   
     *  Attempts to parse the accepted statement and display the 
 492   
     *  parse tree for it.
 493   
     */
 494   
 
 495  0
     private void explainStatement() {
 496   
 
 497  0
         if( parse(accepted(true), 10) || error == null ) {
 498  0
             System.out.println( "parse tree:" );
 499  0
             System.out.println( tree );
 500   
         }
 501   
         else {
 502  0
             System.out.println( "statement does not parse" );
 503   
         }
 504   
     }
 505   
 }
 506   
 
 507