001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1/GPL 2.0
003: *
004: * The contents of this file are subject to the Mozilla Public License Version
005: * 1.1 (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS" basis,
010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: * for the specific language governing rights and limitations under the
012: * License.
013: *
014: * The Original Code is Mozilla Communicator client code, released
015: * March 31, 1998.
016: *
017: * The Initial Developer of the Original Code is
018: * Netscape Communications Corporation.
019: * Portions created by the Initial Developer are Copyright (C) 1998-1999
020: * the Initial Developer. All Rights Reserved.
021: *
022: * Contributor(s):
023: * Christine Begle
024: * Norris Boyd
025: * Roger Lawrence
026: *
027: * Alternatively, the contents of this file may be used under the terms of
028: * the GNU General Public License Version 2 or later (the "GPL"), in which
029: * case the provisions of the GPL are applicable instead of those above. If
030: * you wish to allow use of your version of this file only under the terms of
031: * the GPL and not to allow others to use your version of this file under the
032: * MPL, indicate your decision by deleting the provisions above and replacing
033: * them with the notice and other provisions required by the GPL. If you do
034: * not delete the provisions above, a recipient may use your version of this
035: * file under either the MPL or the GPL.
036: *
037: * ***** END LICENSE BLOCK ***** */
038:
039: package org.mozilla.javascript.tools.jsc;
040:
041: import java.io.*;
042: import java.util.*;
043: import org.mozilla.javascript.*;
044: import org.mozilla.javascript.optimizer.ClassCompiler;
045: import org.mozilla.javascript.tools.ToolErrorReporter;
046:
047: /**
048: * @author Norris Boyd
049: */
050: public class Main {
051:
052: /**
053: * Main entry point.
054: *
055: * Process arguments as would a normal Java program.
056: * Then set up the execution environment and begin to
057: * compile scripts.
058: */
059: public static void main(String args[]) {
060: Main main = new Main();
061: args = main.processOptions(args);
062: if (args == null) {
063: if (main.printHelp) {
064: System.out.println(ToolErrorReporter.getMessage(
065: "msg.jsc.usage", Main.class.getName()));
066: System.exit(0);
067: }
068: System.exit(1);
069: }
070: if (!main.reporter.hasReportedError()) {
071: main.processSource(args);
072: }
073: }
074:
075: public Main() {
076: reporter = new ToolErrorReporter(true);
077: compilerEnv = new CompilerEnvirons();
078: compilerEnv.setErrorReporter(reporter);
079: compiler = new ClassCompiler(compilerEnv);
080: }
081:
082: /**
083: * Parse arguments.
084: *
085: */
086: public String[] processOptions(String args[]) {
087: targetPackage = ""; // default to no package
088: compilerEnv.setGenerateDebugInfo(false); // default to no symbols
089: for (int i = 0; i < args.length; i++) {
090: String arg = args[i];
091: if (!arg.startsWith("-")) {
092: int tail = args.length - i;
093: if (targetName != null && tail > 1) {
094: addError("msg.multiple.js.to.file", targetName);
095: return null;
096: }
097: String[] result = new String[tail];
098: for (int j = 0; j != tail; ++j) {
099: result[j] = args[i + j];
100: }
101: return result;
102: }
103: if (arg.equals("-help") || arg.equals("-h")
104: || arg.equals("--help")) {
105: printHelp = true;
106: return null;
107: }
108:
109: try {
110: if (arg.equals("-version") && ++i < args.length) {
111: int version = Integer.parseInt(args[i]);
112: compilerEnv.setLanguageVersion(version);
113: continue;
114: }
115: if ((arg.equals("-opt") || arg.equals("-O"))
116: && ++i < args.length) {
117: int optLevel = Integer.parseInt(args[i]);
118: compilerEnv.setOptimizationLevel(optLevel);
119: continue;
120: }
121: } catch (NumberFormatException e) {
122: badUsage(args[i]);
123: return null;
124: }
125: if (arg.equals("-nosource")) {
126: compilerEnv.setGeneratingSource(false);
127: continue;
128: }
129: if (arg.equals("-debug") || arg.equals("-g")) {
130: compilerEnv.setGenerateDebugInfo(true);
131: continue;
132: }
133: if (arg.equals("-main-method-class") && ++i < args.length) {
134: compiler.setMainMethodClass(args[i]);
135: continue;
136: }
137: if (arg.equals("-o") && ++i < args.length) {
138: String name = args[i];
139: int end = name.length();
140: if (end == 0
141: || !Character.isJavaIdentifierStart(name
142: .charAt(0))) {
143: addError("msg.invalid.classfile.name", name);
144: continue;
145: }
146: for (int j = 1; j < end; j++) {
147: char c = name.charAt(j);
148: if (!Character.isJavaIdentifierPart(c)) {
149: if (c == '.') {
150: // check if it is the dot in .class
151: if (j == end - 6 && name.endsWith(".class")) {
152: name = name.substring(0, j);
153: break;
154: }
155: }
156: addError("msg.invalid.classfile.name", name);
157: break;
158: }
159: }
160: targetName = name;
161: continue;
162: }
163: if (arg.equals("-observe-instruction-count")) {
164: compilerEnv.setGenerateObserverCount(true);
165: }
166: if (arg.equals("-package") && ++i < args.length) {
167: String pkg = args[i];
168: int end = pkg.length();
169: for (int j = 0; j != end; ++j) {
170: char c = pkg.charAt(j);
171: if (Character.isJavaIdentifierStart(c)) {
172: for (++j; j != end; ++j) {
173: c = pkg.charAt(j);
174: if (!Character.isJavaIdentifierPart(c)) {
175: break;
176: }
177: }
178: if (j == end) {
179: break;
180: }
181: if (c == '.' && j != end - 1) {
182: continue;
183: }
184: }
185: addError("msg.package.name", targetPackage);
186: return null;
187: }
188: targetPackage = pkg;
189: continue;
190: }
191: if (arg.equals("-extends") && ++i < args.length) {
192: String targetExtends = args[i];
193: Class super Class;
194: try {
195: super Class = Class.forName(targetExtends);
196: } catch (ClassNotFoundException e) {
197: throw new Error(e.toString()); // TODO: better error
198: }
199: compiler.setTargetExtends(super Class);
200: continue;
201: }
202: if (arg.equals("-implements") && ++i < args.length) {
203: // TODO: allow for multiple comma-separated interfaces.
204: String targetImplements = args[i];
205: StringTokenizer st = new StringTokenizer(
206: targetImplements, ",");
207: Vector v = new Vector();
208: while (st.hasMoreTokens()) {
209: String className = st.nextToken();
210: try {
211: v.addElement(Class.forName(className));
212: } catch (ClassNotFoundException e) {
213: throw new Error(e.toString()); // TODO: better error
214: }
215: }
216: Class[] implements Classes = new Class[v.size()];
217: v.copyInto(implements Classes);
218: compiler.setTargetImplements(implements Classes);
219: continue;
220: }
221: if (arg.equals("-d") && ++i < args.length) {
222: destinationDir = args[i];
223: continue;
224: }
225: badUsage(arg);
226: return null;
227: }
228: // no file name
229: p(ToolErrorReporter.getMessage("msg.no.file"));
230: return null;
231: }
232:
233: /**
234: * Print a usage message.
235: */
236: private static void badUsage(String s) {
237: System.err.println(ToolErrorReporter.getMessage(
238: "msg.jsc.bad.usage", Main.class.getName(), s));
239: }
240:
241: /**
242: * Compile JavaScript source.
243: *
244: */
245: public void processSource(String[] filenames) {
246: for (int i = 0; i != filenames.length; ++i) {
247: String filename = filenames[i];
248: if (!filename.endsWith(".js")) {
249: addError("msg.extension.not.js", filename);
250: return;
251: }
252: File f = new File(filename);
253: String source = readSource(f);
254: if (source == null)
255: return;
256:
257: String mainClassName = targetName;
258: if (mainClassName == null) {
259: String name = f.getName();
260: String nojs = name.substring(0, name.length() - 3);
261: mainClassName = getClassName(nojs);
262: }
263: if (targetPackage.length() != 0) {
264: mainClassName = targetPackage + "." + mainClassName;
265: }
266:
267: Object[] compiled = compiler.compileToClassFiles(source,
268: filename, 1, mainClassName);
269: if (compiled == null || compiled.length == 0) {
270: return;
271: }
272:
273: File targetTopDir = null;
274: if (destinationDir != null) {
275: targetTopDir = new File(destinationDir);
276: } else {
277: String parent = f.getParent();
278: if (parent != null) {
279: targetTopDir = new File(parent);
280: }
281: }
282: for (int j = 0; j != compiled.length; j += 2) {
283: String className = (String) compiled[j];
284: byte[] bytes = (byte[]) compiled[j + 1];
285: File outfile = getOutputFile(targetTopDir, className);
286: try {
287: FileOutputStream os = new FileOutputStream(outfile);
288: try {
289: os.write(bytes);
290: } finally {
291: os.close();
292: }
293: } catch (IOException ioe) {
294: addFormatedError(ioe.toString());
295: }
296: }
297: }
298: }
299:
300: private String readSource(File f) {
301: if (!f.exists()) {
302: addError("msg.jsfile.not.found", f.getAbsolutePath());
303: return null;
304: }
305: try {
306: Reader in = new FileReader(f);
307: try {
308: return Kit.readReader(in);
309: } finally {
310: in.close();
311: }
312: } catch (FileNotFoundException ex) {
313: addError("msg.couldnt.open", f.getAbsolutePath());
314: } catch (IOException ioe) {
315: addFormatedError(ioe.toString());
316: }
317: return null;
318: }
319:
320: private File getOutputFile(File parentDir, String className) {
321: String path = className.replace('.', File.separatorChar);
322: path = path.concat(".class");
323: File f = new File(parentDir, path);
324: String dirPath = f.getParent();
325: if (dirPath != null) {
326: File dir = new File(dirPath);
327: if (!dir.exists()) {
328: dir.mkdirs();
329: }
330: }
331: return f;
332: }
333:
334: /**
335: * Verify that class file names are legal Java identifiers. Substitute
336: * illegal characters with underscores, and prepend the name with an
337: * underscore if the file name does not begin with a JavaLetter.
338: */
339:
340: String getClassName(String name) {
341: char[] s = new char[name.length() + 1];
342: char c;
343: int j = 0;
344:
345: if (!Character.isJavaIdentifierStart(name.charAt(0))) {
346: s[j++] = '_';
347: }
348: for (int i = 0; i < name.length(); i++, j++) {
349: c = name.charAt(i);
350: if (Character.isJavaIdentifierPart(c)) {
351: s[j] = c;
352: } else {
353: s[j] = '_';
354: }
355: }
356: return (new String(s)).trim();
357: }
358:
359: private static void p(String s) {
360: System.out.println(s);
361: }
362:
363: private void addError(String messageId, String arg) {
364: String msg;
365: if (arg == null) {
366: msg = ToolErrorReporter.getMessage(messageId);
367: } else {
368: msg = ToolErrorReporter.getMessage(messageId, arg);
369: }
370: addFormatedError(msg);
371: }
372:
373: private void addFormatedError(String message) {
374: reporter.error(message, null, -1, null, -1);
375: }
376:
377: private boolean printHelp;
378: private ToolErrorReporter reporter;
379: private CompilerEnvirons compilerEnv;
380: private ClassCompiler compiler;
381: private String targetName;
382: private String targetPackage;
383: private String destinationDir;
384: }
|