KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > Main


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
16  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
17  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
18  * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2004-2006 Charles O Nutter <headius@headius.com>
20  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
21  * Copyright (C) 2005 Kiel Hodges <jruby-devel@selfsosoft.com>
22  * Copyright (C) 2005 Jason Voegele <jason@jvoegele.com>
23  * Copyright (C) 2005 Tim Azzopardi <tim@tigerfive.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the CPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the CPL, the GPL or the LGPL.
36  ***** END LICENSE BLOCK *****/

37 package org.jruby;
38
39 import java.io.InputStream JavaDoc;
40 import java.io.PrintStream JavaDoc;
41 import java.io.Reader JavaDoc;
42 import java.util.Iterator JavaDoc;
43
44 import org.jruby.ast.Node;
45 import org.jruby.exceptions.JumpException;
46 import org.jruby.exceptions.MainExitException;
47 import org.jruby.exceptions.RaiseException;
48 import org.jruby.internal.runtime.ValueAccessor;
49 import org.jruby.javasupport.JavaUtil;
50 import org.jruby.parser.ParserSupport;
51 import org.jruby.runtime.Block;
52 import org.jruby.runtime.Constants;
53 import org.jruby.runtime.IAccessor;
54 import org.jruby.runtime.builtin.IRubyObject;
55 import org.jruby.util.CommandlineParser;
56 import org.jruby.ast.executable.YARVCompiledRunner;
57
58 /**
59  * Class used to launch the interpreter.
60  * This is the main class as defined in the jruby.mf manifest.
61  * It is very basic and does not support yet the same array of switches
62  * as the C interpreter.
63  * Usage: java -jar jruby.jar [switches] [rubyfile.rb] [arguments]
64  * -e 'command' one line of script. Several -e's allowed. Omit [programfile]
65  * @author jpetersen
66  */

67 public class Main {
68     private CommandlineParser commandline;
69     private boolean hasPrintedUsage = false;
70     private RubyInstanceConfig config;
71     // ENEBO: We used to have in, but we do not use it in this class anywhere
72
private PrintStream JavaDoc out;
73     private PrintStream JavaDoc err;
74
75     public Main(RubyInstanceConfig config) {
76         this.config = config;
77         this.out = config.getOutput();
78         this.err = config.getError();
79     }
80
81     public Main(final InputStream JavaDoc in, final PrintStream JavaDoc out, final PrintStream JavaDoc err) {
82         this(new RubyInstanceConfig(){{
83             setInput(in);
84             setOutput(out);
85             setError(err);
86         }});
87     }
88
89     public Main() {
90         this(new RubyInstanceConfig());
91     }
92
93     public static void main(String JavaDoc[] args) {
94         Main main = new Main();
95         int status = main.run(args);
96         if (status != 0) {
97             System.exit(status);
98         }
99     }
100
101     public int run(String JavaDoc[] args) {
102         commandline = new CommandlineParser(this, args);
103
104         if (commandline.isShowVersion()) {
105             showVersion();
106         }
107
108         if (! commandline.shouldRunInterpreter()) {
109             return 0;
110         }
111
112         long now = -1;
113         if (commandline.isBenchmarking()) {
114             now = System.currentTimeMillis();
115         }
116
117         int status;
118
119         try {
120             status = runInterpreter(commandline);
121         } catch (MainExitException mee) {
122             err.println(mee.getMessage());
123             if (mee.isUsageError()) {
124                 printUsage();
125             }
126             status = mee.getStatus();
127         }
128
129         if (commandline.isBenchmarking()) {
130             out.println("Runtime: " + (System.currentTimeMillis() - now) + " ms");
131         }
132
133         return status;
134     }
135
136     private void showVersion() {
137         out.print("ruby ");
138         out.print(Constants.RUBY_VERSION);
139         out.print(" (");
140         out.print(Constants.COMPILE_DATE);
141         out.print(") [");
142         out.print("java-jruby" + Constants.VERSION);
143         out.println("]");
144     }
145
146     public void printUsage() {
147         if (!hasPrintedUsage) {
148             out.println("Usage: jruby [switches] [--] [rubyfile.rb] [arguments]");
149             out.println(" -e 'command' one line of script. Several -e's allowed. Omit [programfile]");
150             out.println(" -b benchmark mode, times the script execution");
151             out.println(" -Idirectory specify $LOAD_PATH directory (may be used more than once)");
152             out.println(" -- optional -- before rubyfile.rb for compatibility with ruby");
153             out.println(" -d set debugging flags (set $DEBUG to true)");
154             out.println(" -v print version number, then turn on verbose mode");
155             out.println(" -O run with ObjectSpace disabled (improves performance)");
156             out.println(" -S cmd run the specified command in JRuby's bin dir");
157             out.println(" -C pre-compile scripts before running (EXPERIMENTAL)");
158             out.println(" -y read a YARV-compiled Ruby script and run that (EXPERIMENTAL)");
159             out.println(" -Y compile a Ruby script into YARV bytecodes and run this (EXPERIMENTAL)");
160             out.println(" --command word Execute ruby-related shell command (i.e., irb, gem)");
161             hasPrintedUsage = true;
162         }
163     }
164
165     private int runInterpreter(CommandlineParser commandline) {
166         Reader JavaDoc reader = commandline.getScriptSource();
167         String JavaDoc filename = commandline.displayedFileName();
168         config.updateWithCommandline(commandline);
169         final Ruby runtime = Ruby.newInstance(config);
170         runtime.setKCode(commandline.getKCode());
171
172         // Add a shutdown hook that dumps the contents of the runtimeInformation map.
173
// This map can be used at development-time to log profiling information
174
// that must be updated as the execution runs.
175
Runtime.getRuntime().addShutdownHook(new Thread JavaDoc() {
176             public void run() {
177                 if (!runtime.getRuntimeInformation().isEmpty()) {
178                     System.err.println("Runtime information dump:");
179
180                     for (Iterator JavaDoc iter = runtime.getRuntimeInformation().keySet().iterator(); iter.hasNext();) {
181                         Object JavaDoc key = iter.next();
182                         System.err.println("[" + key + "]: " + runtime.getRuntimeInformation().get(key));
183                     }
184                 }
185             }
186         });
187
188         try {
189             runInterpreter(runtime, reader, filename);
190             return 0;
191         } catch (JumpException je) {
192             if (je.getJumpType() == JumpException.JumpType.RaiseJump) {
193                 RubyException raisedException = ((RaiseException)je).getException();
194                 if (raisedException.isKindOf(runtime.getClass("SystemExit"))) {
195                     RubyFixnum status = (RubyFixnum)raisedException.getInstanceVariable("status");
196
197                     if (status != null) {
198                         return RubyNumeric.fix2int(status);
199                     } else {
200                         return 0;
201                     }
202                 } else {
203                     runtime.printError(raisedException);
204                     return 1;
205                 }
206             } else if (je.getJumpType() == JumpException.JumpType.ThrowJump) {
207                 return 1;
208             } else {
209                 throw je;
210             }
211         } catch(MainExitException e) {
212             if(e.isAborted()) {
213                 return e.getStatus();
214             } else {
215                 throw e;
216             }
217         }
218     }
219
220     private void runInterpreter(Ruby runtime, Reader JavaDoc reader, String JavaDoc filename) {
221         try {
222             initializeRuntime(runtime, filename);
223             if(commandline.isYARVEnabled()) {
224                 new YARVCompiledRunner(runtime,reader,filename).run();
225             } else {
226                 Node parsedScript = getParsedScript(runtime, reader, filename);
227                 if (commandline.isCompilerEnabled()) {
228                     runtime.compileAndRun(parsedScript);
229                 } else if(commandline.isYARVCompileEnabled()) {
230                     runtime.ycompileAndRun(parsedScript);
231                 } else {
232                     runtime.eval(parsedScript);
233                 }
234             }
235         } finally {
236             runtime.tearDown();
237         }
238     }
239
240     private Node getParsedScript(Ruby runtime, Reader JavaDoc reader, String JavaDoc filename) {
241         // current scope is top-level scope (what we set TOPLEVEL_BINDING to).
242
Node result = runtime.parse(reader, filename, runtime.getCurrentContext().getCurrentScope());
243         if (commandline.isAssumePrinting()) {
244             result = new ParserSupport().appendPrintToBlock(result);
245         }
246         if (commandline.isAssumeLoop()) {
247             result = new ParserSupport().appendWhileLoopToBlock(result, commandline.isProcessLineEnds(), commandline.isSplit());
248         }
249         return result;
250     }
251
252     private void initializeRuntime(final Ruby runtime, String JavaDoc filename) {
253         IRubyObject argumentArray = runtime.newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(runtime, commandline.getScriptArguments()));
254         runtime.setVerbose(runtime.newBoolean(commandline.isVerbose()));
255         runtime.setDebug(runtime.newBoolean(commandline.isDebug()));
256
257         defineGlobalVERBOSE(runtime);
258         defineGlobalDEBUG(runtime);
259
260         runtime.getObject().setConstant("$VERBOSE",
261                 commandline.isVerbose() ? runtime.getTrue() : runtime.getNil());
262         runtime.defineGlobalConstant("ARGV", argumentArray);
263
264         defineGlobal(runtime, "$-p", commandline.isAssumePrinting());
265         defineGlobal(runtime, "$-n", commandline.isAssumeLoop());
266         defineGlobal(runtime, "$-a", commandline.isSplit());
267         defineGlobal(runtime, "$-l", commandline.isProcessLineEnds());
268         runtime.getGlobalVariables().defineReadonly("$*", new ValueAccessor(argumentArray));
269         // TODO this is a fake cause we have no real process number in Java
270
runtime.getGlobalVariables().defineReadonly("$$", new ValueAccessor(runtime.newFixnum(runtime.hashCode())));
271
272         IAccessor d = new ValueAccessor(runtime.newString(filename));
273         runtime.getGlobalVariables().define("$PROGRAM_NAME", d);
274         runtime.getGlobalVariables().define("$0", d);
275
276         runtime.getLoadService().init(commandline.loadPaths());
277         Iterator JavaDoc iter = commandline.requiredLibraries().iterator();
278         while (iter.hasNext()) {
279             String JavaDoc scriptName = (String JavaDoc) iter.next();
280             RubyKernel.require(runtime.getTopSelf(), runtime.newString(scriptName), Block.NULL_BLOCK);
281         }
282     }
283
284     private void defineGlobalVERBOSE(final Ruby runtime) {
285         // $VERBOSE can be true, false, or nil. Any non-false-nil value will get stored as true
286
runtime.getGlobalVariables().define("$VERBOSE", new IAccessor() {
287             public IRubyObject getValue() {
288                 return runtime.getVerbose();
289             }
290
291             public IRubyObject setValue(IRubyObject newValue) {
292                 if (newValue.isNil()) {
293                     runtime.setVerbose(newValue);
294                 } else {
295                     runtime.setVerbose(runtime.newBoolean(newValue != runtime.getFalse()));
296                 }
297
298                 return newValue;
299             }
300         });
301     }
302
303     private void defineGlobalDEBUG(final Ruby runtime) {
304         IAccessor d = new IAccessor() {
305             public IRubyObject getValue() {
306                 return runtime.getDebug();
307             }
308
309             public IRubyObject setValue(IRubyObject newValue) {
310                 if (newValue.isNil()) {
311                     runtime.setDebug(newValue);
312                 } else {
313                     runtime.setDebug(runtime.newBoolean(newValue != runtime.getFalse()));
314                 }
315
316                 return newValue;
317             }
318             };
319         runtime.getGlobalVariables().define("$DEBUG", d);
320         runtime.getGlobalVariables().define("$-d", d);
321     }
322
323     private void defineGlobal(Ruby runtime, String JavaDoc name, boolean value) {
324         runtime.getGlobalVariables().defineReadonly(name, new ValueAccessor(value ? runtime.getTrue() : runtime.getNil()));
325     }
326 }
327
Popular Tags