View Javadoc

1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is Rhino code, released
15   * May 6, 1998.
16   *
17   * The Initial Developer of the Original Code is
18   * Netscape Communications Corporation.
19   * Portions created by the Initial Developer are Copyright (C) 1997-1999
20   * the Initial Developer. All Rights Reserved.
21   *
22   * Contributor(s):
23   *
24   * Alternatively, the contents of this file may be used under the terms of
25   * the GNU General Public License Version 2 or later (the "GPL"), in which
26   * case the provisions of the GPL are applicable instead of those above. If
27   * you wish to allow use of your version of this file only under the terms of
28   * the GPL and not to allow others to use your version of this file under the
29   * MPL, indicate your decision by deleting the provisions above and replacing
30   * them with the notice and other provisions required by the GPL. If you do
31   * not delete the provisions above, a recipient may use your version of this
32   * file under either the MPL or the GPL.
33   *
34   * ***** END LICENSE BLOCK ***** */
35  
36  package net_alchim31_maven_yuicompressor;
37  
38  import java.io.BufferedReader;
39  import java.io.FileInputStream;
40  import java.io.FileNotFoundException;
41  import java.io.FileReader;
42  import java.io.IOException;
43  import java.io.InputStreamReader;
44  
45  import org.codehaus.plexus.util.IOUtil;
46  import org.mozilla.javascript.Context;
47  import org.mozilla.javascript.ErrorReporter;
48  import org.mozilla.javascript.EvaluatorException;
49  import org.mozilla.javascript.Function;
50  import org.mozilla.javascript.JavaScriptException;
51  import org.mozilla.javascript.Scriptable;
52  import org.mozilla.javascript.ScriptableObject;
53  import org.mozilla.javascript.WrappedException;
54  
55  /**
56   * The BasicRhinoShell program.
57   *
58   * Can execute scripts interactively or in batch mode at the command line. An
59   * example of controlling the JavaScript engine.
60   *
61   * @author Norris Boyd
62   * @based http://lxr.mozilla.org/mozilla/source/js/rhino/examples/BasicRhinoShell.java
63   *        (2007-08-30)
64   */
65  @SuppressWarnings("serial")
66  public class BasicRhinoShell extends ScriptableObject {
67  
68      @Override
69      public String getClassName() {
70          return "global";
71      }
72  
73      /**
74       * Main entry point.
75       *
76       * Process arguments as would a normal Java program. Also create a new
77       * Context and associate it with the current thread. Then set up the
78       * execution environment and begin to execute scripts.
79       */
80      public static void exec(String args[], ErrorReporter reporter) {
81          // Associate a new Context with this thread
82          Context cx = Context.enter();
83          cx.setErrorReporter(reporter);
84          try {
85              // Initialize the standard objects (Object, Function, etc.)
86              // This must be done before scripts can be executed.
87              BasicRhinoShell BasicRhinoShell = new BasicRhinoShell();
88              cx.initStandardObjects(BasicRhinoShell);
89  
90              // Define some global functions particular to the BasicRhinoShell.
91              // Note
92              // that these functions are not part of ECMA.
93              String[] names = { "print", "quit", "version", "load", "help", "readFile", "warn" };
94              BasicRhinoShell.defineFunctionProperties(names, BasicRhinoShell.class, ScriptableObject.DONTENUM);
95  
96              args = processOptions(cx, args);
97  
98              // Set up "arguments" in the global scope to contain the command
99              // line arguments after the name of the script to execute
100             Object[] array;
101             if (args.length == 0) {
102                 array = new Object[0];
103             } else {
104                 int length = args.length - 1;
105                 array = new Object[length];
106                 System.arraycopy(args, 1, array, 0, length);
107             }
108             Scriptable argsObj = cx.newArray(BasicRhinoShell, array);
109             BasicRhinoShell.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM);
110 
111             BasicRhinoShell.processSource(cx, args.length == 0 ? null : args[0]);
112         } finally {
113             Context.exit();
114         }
115     }
116 
117     /**
118      * Parse arguments.
119      */
120     public static String[] processOptions(Context cx, String args[]) {
121         for (int i = 0; i < args.length; i++) {
122             String arg = args[i];
123             if (!arg.startsWith("-")) {
124                 String[] result = new String[args.length - i];
125                 for (int j = i; j < args.length; j++) {
126                     result[j - i] = args[j];
127                 }
128                 return result;
129             }
130             if (arg.equals("-version")) {
131                 if (++i == args.length) {
132                     usage(arg);
133                 }
134                 double d = Context.toNumber(args[i]);
135                 if (d != d) {
136                     usage(arg);
137                 }
138                 cx.setLanguageVersion((int) d);
139                 continue;
140             }
141             usage(arg);
142         }
143         return new String[0];
144     }
145 
146     /**
147      * Print a usage message.
148      */
149     private static void usage(String s) {
150         p("Didn't understand \"" + s + "\".");
151         p("Valid arguments are:");
152         p("-version 100|110|120|130|140|150|160|170");
153         System.exit(1);
154     }
155 
156     /**
157      * Print a help message.
158      *
159      * This method is defined as a JavaScript function.
160      */
161     public void help() {
162         p("");
163         p("Command                Description");
164         p("=======                ===========");
165         p("help()                 Display usage and help messages. ");
166         p("defineClass(className) Define an extension using the Java class");
167         p("                       named with the string argument. ");
168         p("                       Uses ScriptableObject.defineClass(). ");
169         p("load(['foo.js', ...])  Load JavaScript source files named by ");
170         p("                       string arguments. ");
171         p("loadClass(className)   Load a class named by a string argument.");
172         p("                       The class must be a script compiled to a");
173         p("                       class file. ");
174         p("print([expr ...])      Evaluate and print expressions. ");
175         p("quit()                 Quit the BasicRhinoShell. ");
176         p("version([number])      Get or set the JavaScript version number.");
177         p("");
178     }
179 
180     /**
181      * Print the string values of its arguments.
182      *
183      * This method is defined as a JavaScript function. Note that its arguments
184      * are of the "varargs" form, which allows it to handle an arbitrary number
185      * of arguments supplied to the JavaScript function.
186      *
187      */
188     public static void print(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
189         for (int i = 0; i < args.length; i++) {
190             if (i > 0) {
191                 System.out.print(" ");
192             }
193 
194             // Convert the arbitrary JavaScript value into a string form.
195             String s = Context.toString(args[i]);
196 
197             System.out.print(s);
198         }
199         System.out.println();
200     }
201 
202     /**
203      * Quit the BasicRhinoShell.
204      *
205      * This only affects the interactive mode.
206      *
207      * This method is defined as a JavaScript function.
208      */
209     public void quit() {
210         quitting = true;
211     }
212 
213     public static void warn(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
214         String message = Context.toString( args[ 0 ] );
215         int line = (int) Context.toNumber( args[ 1 ] );
216         String source = Context.toString( args[ 2 ] );
217         int column = (int) Context.toNumber( args[ 3 ] );
218         cx.getErrorReporter().warning( message, null, line, source, column );
219     }
220 
221     /**
222      * This method is defined as a JavaScript function.
223      */
224     public String readFile(String path) {
225         try {
226             return IOUtil.toString(new FileInputStream(path));
227         } catch (RuntimeException exc) {
228             throw exc;
229         } catch (Exception exc) {
230             throw new RuntimeException("wrap: " + exc.getMessage(), exc);
231         }
232     }
233 
234     /**
235      * Get and set the language version.
236      *
237      * This method is defined as a JavaScript function.
238      */
239     public static double version(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
240         double result = cx.getLanguageVersion();
241         if (args.length > 0) {
242             double d = Context.toNumber(args[0]);
243             cx.setLanguageVersion((int) d);
244         }
245         return result;
246     }
247 
248     /**
249      * Load and execute a set of JavaScript source files.
250      *
251      * This method is defined as a JavaScript function.
252      *
253      */
254     public static void load(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
255         BasicRhinoShell BasicRhinoShell = (BasicRhinoShell) getTopLevelScope(thisObj);
256         for (Object element : args) {
257             BasicRhinoShell.processSource(cx, Context.toString(element));
258         }
259     }
260 
261     /**
262      * Evaluate JavaScript source.
263      *
264      * @param cx the current context
265      * @param filename the name of the file to compile, or null for interactive
266      *            mode.
267      */
268     private void processSource(Context cx, String filename) {
269         if (filename == null) {
270             BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
271             String sourceName = "<stdin>";
272             int lineno = 1;
273             boolean hitEOF = false;
274             do {
275                 int startline = lineno;
276                 System.err.print("js> ");
277                 System.err.flush();
278                 try {
279                     String source = "";
280                     // Collect lines of source to compile.
281                     while (true) {
282                         String newline;
283                         newline = in.readLine();
284                         if (newline == null) {
285                             hitEOF = true;
286                             break;
287                         }
288                         source = source + newline + "\n";
289                         lineno++;
290                         // Continue collecting as long as more lines
291                         // are needed to complete the current
292                         // statement. stringIsCompilableUnit is also
293                         // true if the source statement will result in
294                         // any error other than one that might be
295                         // resolved by appending more source.
296                         if (cx.stringIsCompilableUnit(source)) {
297                             break;
298                         }
299                     }
300                     Object result = cx.evaluateString(this, source, sourceName, startline, null);
301                     if (result != Context.getUndefinedValue()) {
302                         System.err.println(Context.toString(result));
303                     }
304                 } catch (WrappedException we) {
305                     // Some form of exception was caught by JavaScript and
306                     // propagated up.
307                     System.err.println(we.getWrappedException().toString());
308                     we.printStackTrace();
309                 } catch (EvaluatorException ee) {
310                     // Some form of JavaScript error.
311                     System.err.println("js: " + ee.getMessage());
312                 } catch (JavaScriptException jse) {
313                     // Some form of JavaScript error.
314                     System.err.println("js: " + jse.getMessage());
315                 } catch (IOException ioe) {
316                     System.err.println(ioe.toString());
317                 }
318                 if (quitting) {
319                     // The user executed the quit() function.
320                     break;
321                 }
322             } while (!hitEOF);
323             System.err.println();
324         } else {
325             FileReader in = null;
326             try {
327                 in = new FileReader(filename);
328             } catch (FileNotFoundException ex) {
329                 Context.reportError("Couldn't open file \"" + filename + "\".");
330                 return;
331             }
332 
333             try {
334                 // Here we evalute the entire contents of the file as
335                 // a script. Text is printed only if the print() function
336                 // is called.
337                 cx.evaluateReader(this, in, filename, 1, null);
338             } catch (WrappedException we) {
339                 System.err.println(we.getWrappedException().toString());
340                 we.printStackTrace();
341             } catch (EvaluatorException ee) {
342                 System.err.println("js: " + ee.getMessage());
343             } catch (JavaScriptException jse) {
344                 System.err.println("js: " + jse.getMessage());
345             } catch (IOException ioe) {
346                 System.err.println(ioe.toString());
347             } finally {
348                 try {
349                     in.close();
350                 } catch (IOException ioe) {
351                     System.err.println(ioe.toString());
352                 }
353             }
354         }
355     }
356 
357     private static void p(String s) {
358         System.out.println(s);
359     }
360 
361     private boolean quitting;
362 }