forked from mozilla/rhino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShell.java
285 lines (264 loc) · 10.6 KB
/
Shell.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
/**
* The shell program.
*
* <p>Can execute scripts interactively or in batch mode at the command line. An example of
* controlling the JavaScript engine.
*
* @author Norris Boyd
*/
public class Shell extends ScriptableObject {
private static final long serialVersionUID = -5638074146250193112L;
@Override
public String getClassName() {
return "global";
}
/**
* Main entry point.
*
* <p>Process arguments as would a normal Java program. Also create a new Context and associate
* it with the current thread. Then set up the execution environment and begin to execute
* scripts.
*/
public static void main(String args[]) {
// Associate a new Context with this thread
Context cx = Context.enter();
try {
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed.
Shell shell = new Shell();
cx.initStandardObjects(shell);
// Define some global functions particular to the shell. Note
// that these functions are not part of ECMA.
String[] names = {"print", "quit", "version", "load", "help"};
shell.defineFunctionProperties(names, Shell.class, ScriptableObject.DONTENUM);
args = processOptions(cx, args);
// Set up "arguments" in the global scope to contain the command
// line arguments after the name of the script to execute
Object[] array;
if (args.length == 0) {
array = new Object[0];
} else {
int length = args.length - 1;
array = new Object[length];
System.arraycopy(args, 1, array, 0, length);
}
Scriptable argsObj = cx.newArray(shell, array);
shell.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM);
shell.processSource(cx, args.length == 0 ? null : args[0]);
} finally {
Context.exit();
}
}
/** Parse arguments. */
public static String[] processOptions(Context cx, String args[]) {
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (!arg.startsWith("-")) {
String[] result = new String[args.length - i];
for (int j = i; j < args.length; j++) result[j - i] = args[j];
return result;
}
if (arg.equals("-version")) {
if (++i == args.length) usage(arg);
double d = Context.toNumber(args[i]);
if (d != d) usage(arg);
cx.setLanguageVersion((int) d);
continue;
}
usage(arg);
}
return new String[0];
}
/** Print a usage message. */
private static void usage(String s) {
p("Didn't understand \"" + s + "\".");
p("Valid arguments are:");
p("-version 100|110|120|130|140|150|160|170");
System.exit(1);
}
/**
* Print a help message.
*
* <p>This method is defined as a JavaScript function.
*/
public void help() {
p("");
p("Command Description");
p("======= ===========");
p("help() Display usage and help messages. ");
p("defineClass(className) Define an extension using the Java class");
p(" named with the string argument. ");
p(" Uses ScriptableObject.defineClass(). ");
p("load(['foo.js', ...]) Load JavaScript source files named by ");
p(" string arguments. ");
p("loadClass(className) Load a class named by a string argument.");
p(" The class must be a script compiled to a");
p(" class file. ");
p("print([expr ...]) Evaluate and print expressions. ");
p("quit() Quit the shell. ");
p("version([number]) Get or set the JavaScript version number.");
p("");
}
/**
* Print the string values of its arguments.
*
* <p>This method is defined as a JavaScript function. Note that its arguments are of the
* "varargs" form, which allows it to handle an arbitrary number of arguments supplied to the
* JavaScript function.
*/
public static void print(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
for (int i = 0; i < args.length; i++) {
if (i > 0) System.out.print(" ");
// Convert the arbitrary JavaScript value into a string form.
String s = Context.toString(args[i]);
System.out.print(s);
}
System.out.println();
}
/**
* Quit the shell.
*
* <p>This only affects the interactive mode.
*
* <p>This method is defined as a JavaScript function.
*/
public void quit() {
quitting = true;
}
/**
* Get and set the language version.
*
* <p>This method is defined as a JavaScript function.
*/
public static double version(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
double result = cx.getLanguageVersion();
if (args.length > 0) {
double d = Context.toNumber(args[0]);
cx.setLanguageVersion((int) d);
}
return result;
}
/**
* Load and execute a set of JavaScript source files.
*
* <p>This method is defined as a JavaScript function.
*/
public static void load(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
Shell shell = (Shell) getTopLevelScope(thisObj);
for (int i = 0; i < args.length; i++) {
shell.processSource(cx, Context.toString(args[i]));
}
}
/**
* Evaluate JavaScript source.
*
* @param cx the current context
* @param filename the name of the file to compile, or null for interactive mode.
*/
private void processSource(Context cx, String filename) {
if (filename == null) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String sourceName = "<stdin>";
int lineno = 1;
boolean hitEOF = false;
do {
int startline = lineno;
System.err.print("js> ");
System.err.flush();
try {
String source = "";
// Collect lines of source to compile.
while (true) {
String newline;
newline = in.readLine();
if (newline == null) {
hitEOF = true;
break;
}
source = source + newline + "\n";
lineno++;
// Continue collecting as long as more lines
// are needed to complete the current
// statement. stringIsCompilableUnit is also
// true if the source statement will result in
// any error other than one that might be
// resolved by appending more source.
if (cx.stringIsCompilableUnit(source)) break;
}
Object result = cx.evaluateString(this, source, sourceName, startline, null);
if (result != Context.getUndefinedValue()) {
System.err.println(Context.toString(result));
}
} catch (WrappedException we) {
// Some form of exception was caught by JavaScript and
// propagated up.
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
} catch (EvaluatorException ee) {
// Some form of JavaScript error.
System.err.println("js: " + ee.getMessage());
} catch (JavaScriptException jse) {
// Some form of JavaScript error.
System.err.println("js: " + jse.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
if (quitting) {
// The user executed the quit() function.
break;
}
} while (!hitEOF);
System.err.println();
} else {
FileReader in = null;
try {
in = new FileReader(filename);
} catch (FileNotFoundException ex) {
Context.reportError("Couldn't open file \"" + filename + "\".");
return;
}
try {
// Here we evalute the entire contents of the file as
// a script. Text is printed only if the print() function
// is called.
cx.evaluateReader(this, in, filename, 1, null);
} catch (WrappedException we) {
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
} catch (EvaluatorException ee) {
System.err.println("js: " + ee.getMessage());
} catch (JavaScriptException jse) {
System.err.println("js: " + jse.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.toString());
} finally {
try {
in.close();
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
}
}
private static void p(String s) {
System.out.println(s);
}
private boolean quitting;
}