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