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 Rhino code, released
015: * May 6, 1999.
016: *
017: * The Initial Developer of the Original Code is
018: * Netscape Communications Corporation.
019: * Portions created by the Initial Developer are Copyright (C) 1997-2000
020: * the Initial Developer. All Rights Reserved.
021: *
022: * Contributor(s):
023: * Igor Bukanov
024: *
025: * Alternatively, the contents of this file may be used under the terms of
026: * the GNU General Public License Version 2 or later (the "GPL"), in which
027: * case the provisions of the GPL are applicable instead of those above. If
028: * you wish to allow use of your version of this file only under the terms of
029: * the GPL and not to allow others to use your version of this file under the
030: * MPL, indicate your decision by deleting the provisions above and replacing
031: * them with the notice and other provisions required by the GPL. If you do
032: * not delete the provisions above, a recipient may use your version of this
033: * file under either the MPL or the GPL.
034: *
035: * ***** END LICENSE BLOCK ***** */
036:
037: package org.mozilla.javascript.optimizer;
038:
039: import org.mozilla.javascript.*;
040:
041: /**
042: * Generates class files from script sources.
043: *
044: * since 1.5 Release 5
045: * @author Igor Bukanov
046: */
047:
048: public class ClassCompiler {
049: /**
050: * Construct ClassCompiler that uses the specified compiler environment
051: * when generating classes.
052: */
053: public ClassCompiler(CompilerEnvirons compilerEnv) {
054: if (compilerEnv == null)
055: throw new IllegalArgumentException();
056: this .compilerEnv = compilerEnv;
057: this .mainMethodClassName = Codegen.DEFAULT_MAIN_METHOD_CLASS;
058: }
059:
060: /**
061: * Set the class name to use for main method implementation.
062: * The class must have a method matching
063: * <tt>public static void main(Script sc, String[] args)</tt>, it will be
064: * called when <tt>main(String[] args)</tt> is called in the generated
065: * class. The class name should be fully qulified name and include the
066: * package name like in <tt>org.foo.Bar<tt>.
067: */
068: public void setMainMethodClass(String className) {
069: // XXX Should this check for a valid class name?
070: mainMethodClassName = className;
071: }
072:
073: /**
074: * Get the name of the class for main method implementation.
075: * @see #setMainMethodClass(String)
076: */
077: public String getMainMethodClass() {
078: return mainMethodClassName;
079: }
080:
081: /**
082: * Get the compiler environment the compiler uses.
083: */
084: public CompilerEnvirons getCompilerEnv() {
085: return compilerEnv;
086: }
087:
088: /**
089: * Get the class that the generated target will extend.
090: */
091: public Class getTargetExtends() {
092: return targetExtends;
093: }
094:
095: /**
096: * Set the class that the generated target will extend.
097: *
098: * @param extendsClass the class it extends
099: */
100: public void setTargetExtends(Class extendsClass) {
101: targetExtends = extendsClass;
102: }
103:
104: /**
105: * Get the interfaces that the generated target will implement.
106: */
107: public Class[] getTargetImplements() {
108: return targetImplements == null ? null
109: : (Class[]) targetImplements.clone();
110: }
111:
112: /**
113: * Set the interfaces that the generated target will implement.
114: *
115: * @param implementsClasses an array of Class objects, one for each
116: * interface the target will extend
117: */
118: public void setTargetImplements(Class[] implements Classes) {
119: targetImplements = implements Classes == null ? null
120: : (Class[]) implements Classes.clone();
121: }
122:
123: /**
124: * Build class name for a auxiliary class generated by compiler.
125: * If the compiler needs to generate extra classes beyond the main class,
126: * it will call this function to build the auxiliary class name.
127: * The default implementation simply appends auxMarker to mainClassName
128: * but this can be overridden.
129: */
130: protected String makeAuxiliaryClassName(String mainClassName,
131: String auxMarker) {
132: return mainClassName + auxMarker;
133: }
134:
135: /**
136: * Compile JavaScript source into one or more Java class files.
137: * The first compiled class will have name mainClassName.
138: * If the results of {@link #getTargetExtends()} or
139: * {@link #getTargetImplements()} are not null, then the first compiled
140: * class will extend the specified super class and implement
141: * specified interfaces.
142: *
143: * @return array where elements with even indexes specifies class name
144: * and the following odd index gives class file body as byte[]
145: * array. The initial element of the array always holds
146: * mainClassName and array[1] holds its byte code.
147: */
148: public Object[] compileToClassFiles(String source,
149: String sourceLocation, int lineno, String mainClassName) {
150: Parser p = new Parser(compilerEnv, compilerEnv
151: .getErrorReporter());
152: ScriptOrFnNode tree = p.parse(source, sourceLocation, lineno);
153: String encodedSource = p.getEncodedSource();
154:
155: Class super Class = getTargetExtends();
156: Class[] interfaces = getTargetImplements();
157: String scriptClassName;
158: boolean isPrimary = (interfaces == null && super Class == null);
159: if (isPrimary) {
160: scriptClassName = mainClassName;
161: } else {
162: scriptClassName = makeAuxiliaryClassName(mainClassName, "1");
163: }
164:
165: Codegen codegen = new Codegen();
166: codegen.setMainMethodClass(mainMethodClassName);
167: byte[] scriptClassBytes = codegen.compileToClassFile(
168: compilerEnv, scriptClassName, tree, encodedSource,
169: false);
170:
171: if (isPrimary) {
172: return new Object[] { scriptClassName, scriptClassBytes };
173: }
174: int functionCount = tree.getFunctionCount();
175: ObjToIntMap functionNames = new ObjToIntMap(functionCount);
176: for (int i = 0; i != functionCount; ++i) {
177: FunctionNode ofn = tree.getFunctionNode(i);
178: String name = ofn.getFunctionName();
179: if (name != null && name.length() != 0) {
180: functionNames.put(name, ofn.getParamCount());
181: }
182: }
183: if (super Class == null) {
184: super Class = ScriptRuntime.ObjectClass;
185: }
186: byte[] mainClassBytes = JavaAdapter.createAdapterCode(
187: functionNames, mainClassName, super Class, interfaces,
188: scriptClassName);
189:
190: return new Object[] { mainClassName, mainClassBytes,
191: scriptClassName, scriptClassBytes };
192: }
193:
194: private String mainMethodClassName;
195: private CompilerEnvirons compilerEnv;
196: private Class targetExtends;
197: private Class[] targetImplements;
198:
199: }
|