001: /* -*- mode: Java; c-basic-offset: 2; -*- */
002:
003: /**
004: * Main entry point for the Javascript compiler
005: *
006: * @author osteele@osteele.com
007: * @author ptw@openlaszlo.org
008: * @author bshine@openlaszlo.org
009: */package org.openlaszlo.sc;
010:
011: import java.io.*;
012: import java.util.*;
013: import java.text.DecimalFormat; // swf writing support
014: import org.openlaszlo.iv.flash.api.FlashFile;
015: import org.openlaszlo.iv.flash.api.Script;
016: import org.openlaszlo.iv.flash.api.action.Program;
017: import org.openlaszlo.iv.flash.api.Frame;
018: import org.openlaszlo.iv.flash.api.action.DoAction;
019: import org.openlaszlo.iv.flash.util.FlashOutput;
020: import org.openlaszlo.iv.flash.util.FlashBuffer;
021: import org.openlaszlo.utils.FileUtils; //
022: import org.openlaszlo.sc.Compiler;
023: import org.openlaszlo.server.LPS;
024:
025: public class lzsc {
026: private static final String[] USAGE = {
027: "Usage: lzsc [options] scriptfile",
028: "",
029: "Options:",
030: "--help",
031: " Prints this message.",
032: "--runtime=(swf7|swf8|swf9|dhtml|j2me|svg)",
033: " specify which runtime to compile code to. Only swf7, swf8, and dhtml are supported",
034: "--debug",
035: " include debugging information in output file",
036: "--profile",
037: " include profiling information in output file",
038: "--Dname=value", " set a compile-time constant",
039: "--option compilerOption[=value]",
040: " set a compiler option", "--incremental",
041: " for LFC debugging, not supported", "--delete",
042: " for LFC debugging, not supported", "",
043: "Output options:", "-o outputfile" };
044:
045: /**
046: * Compiles a Javascript file to the output file for the specified runtime. This method is for command-line invocation of the script compiler.
047: */
048: public static void main(String[] argv) {
049: lzsc compiler = new lzsc();
050: System.exit(compiler.compile(argv));
051: }
052:
053: /**
054: * Prints usage string
055: */
056: public void usage(String msg) {
057: if (msg != null) {
058: System.err.println("Error: " + msg);
059: System.err.println("Use --help for more information");
060: } else {
061: for (int j = 0; j < USAGE.length; j++) {
062: System.err.println(USAGE[j]);
063: }
064: }
065: }
066:
067: /**
068: * Include file resolver
069: */
070: static class Resolver {
071: File base;
072:
073: Resolver(String base) {
074: this .base = new File(base).getParentFile();
075: }
076:
077: String resolve(String pathname) {
078: return (new File(this .base, pathname)).getPath();
079: }
080: }
081:
082: /**
083: * Interface to the compiler
084: */
085: public int compile(String outf, String scriptfile, Map options)
086: throws Exception {
087: // Default options for LFC compiling
088: options.put("flashCompilerCompatability", Boolean.TRUE);
089: options.put("processIncludes", Boolean.TRUE);
090: options.put("resolver", new Resolver(scriptfile));
091:
092: try {
093: Compiler c = new Compiler(options);
094: InputStream f = null;
095: byte[] bytes;
096: try {
097: f = new FileInputStream(scriptfile);
098: bytes = new byte[f.available()];
099: f.read(bytes);
100: bytes = c.compile(("#file " + scriptfile
101: + "\n#line 1\n" + new String(bytes)));
102: } finally {
103: if (f != null) {
104: f.close();
105: }
106: }
107:
108: String runtime = (String) options.get(Compiler.RUNTIME);
109: // Must be kept in sync with server/src/org/openlaszlo/compiler/Compiler.java creatObjectWriter
110: if ("dhtml".equals(runtime) || "j2me".equals(runtime)
111: || "svg".equals(runtime) || "swf9".equals(runtime)) {
112: OutputStream ostr = new FileOutputStream(outf);
113: try {
114: ostr.write(bytes);
115: } finally {
116: ostr.close();
117: }
118: return 0;
119: } else if ("swf7".equals(runtime) || "swf8".equals(runtime)) {
120: // new a Flash file, stuff bytes into it
121: FlashFile newfile = FlashFile.newFlashFile();
122: if ("swf7".equals(runtime)) {
123: newfile.setVersion(7);
124: } else if ("swf8".equals(runtime)) {
125: newfile.setVersion(8);
126: }
127:
128: Script mainScript = new Script(1);
129: mainScript.setMain();
130: newfile.setMainScript(mainScript);
131: Frame frame = newfile.getMainScript().getFrameAt(0);
132: Program program = new Program(bytes, 0, bytes.length);
133: DoAction block = new DoAction(program);
134: frame.addFlashObject(block);
135: FlashOutput flashbuf = newfile.generate();
136: InputStream instream = flashbuf.getInputStream();
137:
138: OutputStream outstream = new FileOutputStream(outf);
139: FileUtils.send(instream, outstream);
140: ;
141: outstream.close();
142: } else {
143: throw new RuntimeException("don't know runtime "
144: + runtime);
145: }
146: } catch (IOException e) {
147: System.err.println("IOException compiling scriptfile "
148: + scriptfile);
149: throw e;
150: } catch (Exception e) {
151: System.err.println("Exception compiling scriptfile: "
152: + e.getMessage());
153: throw e;
154: }
155: return 0;
156: }
157:
158: Map compileTimeConstants = new HashMap();
159: Map compilerOptions = new HashMap();
160:
161: // Must be kept in sync with server/src/org/openlaszlo/compiler/Compiler.java compile
162: boolean setRuntime(String runtime) {
163: if (!("dhtml".equals(runtime) || "j2me".equals(runtime)
164: || "svg".equals(runtime) || "swf9".equals(runtime)
165: || "swf7".equals(runtime) || "swf8".equals(runtime))) {
166: usage("runtime must be one of swf7, swf8, swf9, dhtml, j2me, svg");
167: return false;
168: }
169: compileTimeConstants.put("$runtime", runtime);
170:
171: // Kludges until compile-time constants can be expressions
172: compileTimeConstants.put("$swf7", Boolean.valueOf("swf7"
173: .equals(runtime)));
174: compileTimeConstants.put("$swf8", Boolean.valueOf("swf8"
175: .equals(runtime)));
176: compileTimeConstants.put("$as2", Boolean.valueOf("swf7"
177: .equals(runtime)
178: || "swf8".equals(runtime) || "swf9".equals(runtime)));
179: compileTimeConstants.put("$swf9", Boolean.valueOf("swf9"
180: .equals(runtime)));
181: compileTimeConstants.put("$as3", Boolean.valueOf("swf9"
182: .equals(runtime)));
183: compileTimeConstants.put("$dhtml", Boolean.valueOf("dhtml"
184: .equals(runtime)));
185: compileTimeConstants.put("$j2me", Boolean.valueOf("j2me"
186: .equals(runtime)));
187: compileTimeConstants.put("$svg", Boolean.valueOf("svg"
188: .equals(runtime)));
189: compileTimeConstants.put("$js1", Boolean.valueOf("dhtml"
190: .equals(runtime)
191: || "j2me".equals(runtime) || "svg".equals(runtime)));
192:
193: compilerOptions.put(Compiler.RUNTIME, runtime);
194: return true;
195: }
196:
197: static DecimalFormat secondsFormatter = new DecimalFormat("0.00");
198:
199: /**
200: * Command-line interface, but returns a status rather than exiting
201: */
202: public int compile(String[] argv) {
203: String outf = null;
204: boolean deleteFile = false;
205: String scriptFile = null;
206: boolean incremental = false;
207:
208: String defaultRuntime = LPS.getProperty(
209: "compiler.runtime.default", "swf7");
210: // default constants
211: compileTimeConstants.put("$debug", Boolean.FALSE);
212: compileTimeConstants.put("$profile", Boolean.FALSE);
213:
214: // default options
215: compilerOptions.put(Compiler.CONDITIONAL_COMPILATION,
216: Boolean.TRUE);
217: compilerOptions.put(Compiler.CACHE_COMPILES, Boolean.TRUE);
218:
219: // set default runtime
220: if (!setRuntime(defaultRuntime)) {
221: return 1;
222: }
223:
224: List args = new ArrayList();
225:
226: for (Iterator i = Arrays.asList(argv).iterator(); i.hasNext();) {
227: String opt = (String) i.next();
228: String arg = null;
229: // primitive getopt(args, "D:o:hgpk",
230: // {"help", "incremental", "default=", "delete","runtime=",
231: // "debug", "profile", "krank", "option="})
232: if (opt.startsWith("-D") || opt.startsWith("-o")) {
233: if (opt.length() > 2) {
234: arg = opt.substring(2, opt.length());
235: opt = opt.substring(0, 2);
236: } else {
237: if (!i.hasNext()) {
238: usage(opt + " requires an argument");
239: return 1;
240: }
241: arg = (String) i.next();
242: }
243: } else if (opt.startsWith("--default")
244: || opt.startsWith("--runtime")
245: || opt.startsWith("--option")) {
246: int eq = opt.indexOf("=");
247: if (eq > 0) {
248: arg = opt.substring(eq + 1, opt.length());
249: opt = opt.substring(0, eq);
250: } else {
251: if (!i.hasNext()) {
252: usage(opt + " requires an argument");
253: return 1;
254: }
255: arg = (String) i.next();
256: }
257: }
258: if ("-h".equals(opt) || "--help".equals(opt)) {
259: usage(null);
260: return 0;
261: } else if ("-o".equals(opt)) {
262: outf = arg;
263: } else if ("-D".equals(opt)) {
264: int eq = arg.indexOf("=");
265: if (eq < 0) {
266: usage("-D requires a identifier=value expression");
267: return 1;
268: }
269: String key = arg.substring(0, eq);
270: String value = arg.substring(eq + 1, arg.length());
271: // true and false get coerced to booleans...
272: if ("true".equals(value) || "false".equals(value)) {
273: compileTimeConstants.put(key, Boolean
274: .valueOf(value));
275: } else {
276: compileTimeConstants.put(key, value);
277: }
278: } else if ("--default".equals(opt)) {
279: scriptFile = arg;
280: } else if ("--delete".equals(opt)) {
281: deleteFile = true;
282: } else if ("--incremental".equals(opt)) {
283: incremental = true;
284: compilerOptions.put("cacheCompiles", Boolean.TRUE);
285: compilerOptions.put("progress", Boolean.TRUE);
286: } else if ("--option".equals(opt)) {
287: int eq = arg.indexOf("=");
288: if (eq < 0) {
289: compilerOptions.put(arg, Boolean.TRUE);
290: } else {
291: String key = arg.substring(0, eq);
292: String value = arg.substring(eq + 1, arg.length());
293: // true and false get coerced to booleans...
294: if ("true".equals(value) || "false".equals(value)) {
295: compilerOptions
296: .put(key, Boolean.valueOf(value));
297: } else {
298: compilerOptions.put(key, value);
299: }
300: }
301: } else if ("-g".equals(opt) || "--debug".equals(opt)) {
302: compilerOptions.put("debug", Boolean.TRUE);
303: compileTimeConstants.put("$debug", Boolean.TRUE);
304: } else if ("-p".equals(opt) || "--profile".equals(opt)) {
305: compilerOptions.put("profile", Boolean.TRUE);
306: compileTimeConstants.put("$profile", Boolean.TRUE);
307: } else if ("--runtime".equals(opt)) {
308: if (!setRuntime(arg)) {
309: return 1;
310: }
311: } else {
312: args.add(opt);
313: }
314: }
315: compilerOptions.put("compileTimeConstants",
316: compileTimeConstants);
317: if (outf == null) {
318: usage(" -o is required");
319: return 1;
320: }
321: if (args.size() == 0 && scriptFile != null) {
322: args.add(scriptFile);
323: }
324: if (args.size() != 1) {
325: usage("exactly one file argument is required");
326: return 1;
327: }
328: while (true) {
329: if (deleteFile) {
330: File f = new File(outf);
331: if (f.exists()) {
332: f.delete();
333: }
334: }
335: long time = System.currentTimeMillis();
336: try {
337: compile(outf,
338: ((String[]) args.toArray(new String[0]))[0],
339: compilerOptions);
340: } catch (Exception e) {
341: e.printStackTrace(System.err);
342: System.err.println("Compilation aborted.");
343: if (!incremental) {
344: return 1;
345: }
346: }
347: time = System.currentTimeMillis() - time;
348: if (!incremental) {
349: break;
350: }
351: System.err.println("Compiled " + outf + " in "
352: + secondsFormatter.format(time / 1000.0)
353: + " seconds");
354: System.err.println("Compile again [Enter | q + Enter]: ");
355: // TODO [2007-01-22 ptw]
356: String response = ""; // = new String(System.in.read()).toLower();
357: if ("q".equals(response)) {
358: break;
359: }
360: }
361: return 0;
362: }
363:
364: /**
365: * Stub for interactive testing
366: */
367: int test() {
368: String lfcPath = "../../lfc";
369: return compile(new String[] {
370: "-o",
371: lfcPath + "/LFC7-debug.lzl",
372: // "--option", "nameFunctions=true", "-D$debug=true",
373: "--option", "generateFunction2=true", "--option",
374: "cacheCompiles=true", "--option", "progress=true",
375: "--option", "warnGlobalAssignments=true",
376: "--runtime=dhtml", lfcPath + "/LaszloLibrary.as" });
377: }
378:
379: }
380:
381: /**
382: * @copyright Copyright 2007 Laszlo Systems, Inc. All Rights
383: * Reserved. Use is subject to license terms.
384: */
|