rhino/rhino-dojo.patch
OBS User autobuild f8bb4c968b Accepting request 24642 from Java:packages
Copy from Java:packages/rhino based on submit request 24642 from user mvyskocil

OBS-URL: https://build.opensuse.org/request/show/24642
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/rhino?expand=0&rev=6
2009-11-23 10:42:15 +00:00

1730 lines
58 KiB
Diff

Index: src/org/mozilla/javascript/BaseFunction.java
===================================================================
--- src/org/mozilla/javascript/BaseFunction.java.orig 2009-11-16 15:55:50.222561412 +0100
+++ src/org/mozilla/javascript/BaseFunction.java 2009-11-16 15:56:40.070560339 +0100
@@ -401,6 +401,28 @@
return sb.toString();
}
+ String compress(int indent, int flags)
+ {
+ StringBuffer sb = new StringBuffer();
+ String FuncName = null;
+ boolean justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
+ if (!justbody) {
+ sb.append("function");
+ FuncName = getFunctionName();
+ if(FuncName.length()>0){
+ sb.append(" "+FuncName);
+ }
+ sb.append("(){");
+ }
+ sb.append("[native code, arity=");
+ sb.append(getArity());
+ sb.append("]");
+ if (!justbody) {
+ sb.append("}");
+ }
+ return sb.toString();
+ }
+
public int getArity() { return 0; }
public int getLength() { return 0; }
Index: src/org/mozilla/javascript/Context.java
===================================================================
--- src/org/mozilla/javascript/Context.java.orig 2009-11-16 15:55:50.222561412 +0100
+++ src/org/mozilla/javascript/Context.java 2009-11-16 15:56:40.070560339 +0100
@@ -1241,6 +1241,33 @@
this, scope, args);
}
+ public final String decompileReader(Scriptable scope, Reader in,
+ String sourceName, int lineno,
+ Object securityDomain)
+ throws IOException
+ {
+ Script script = compileReader(scope, in, sourceName, lineno,
+ securityDomain);
+ if (script != null) {
+ // System.err.println(script);
+ return decompileScript(script, 0);
+ } else {
+ return null;
+ }
+ }
+
+ public final String compressReader(Scriptable scope, Script script, String source,
+ String sourceName, int lineno, Object securityDomain){
+
+ if (script != null) {
+ // System.err.println(script);
+ return compressScript(script, 0, source,lineno);
+ } else {
+ return null;
+ }
+ }
+
+
/**
* Check whether a string is ready to be compiled.
* <p>
@@ -1424,6 +1451,27 @@
}
/**
+ * Compress the script.
+ * <p>
+ * Compressed script is returned.
+ *
+ * @param script the script object
+ * @param indent the number of spaces to indent the result
+ * @return a string representing the script source
+ */
+ public final String compressScript(Script script, int indent, String source,int lineno)
+ {
+ NativeFunction scriptImpl = (NativeFunction) script;
+
+ CompilerEnvirons compilerEnv = new CompilerEnvirons();
+
+ Parser parser = new Parser(compilerEnv, compilerEnv.getErrorReporter());
+
+ ScriptOrFnNode tree = parser.parse(source, null, lineno);
+
+ return scriptImpl.compress( tree,indent, 0);
+ }
+ /**
* Decompile a JavaScript Function.
* <p>
* Decompiles a previously compiled JavaScript function object to
@@ -2358,7 +2406,6 @@
sourceReader = null;
}
}
-
Parser p = new Parser(compilerEnv, compilationErrorReporter);
if (returnFunction) {
p.calledByCompileFunction = true;
@@ -2369,6 +2416,7 @@
} else {
tree = p.parse(sourceReader, sourceName, lineno);
}
+
if (returnFunction) {
if (!(tree.getFunctionCount() == 1
&& tree.getFirstChild() != null
Index: src/org/mozilla/javascript/Decompiler.java
===================================================================
--- src/org/mozilla/javascript/Decompiler.java.orig 2009-11-16 15:55:50.222561412 +0100
+++ src/org/mozilla/javascript/Decompiler.java 2009-11-16 15:56:40.082560417 +0100
@@ -41,6 +41,11 @@
package org.mozilla.javascript;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
/**
* The following class save decompilation information about the source.
* Source information is returned from the parser as a String
@@ -74,6 +79,264 @@
* the final constant pool entry from information available at parse
* time.
*/
+
+class TokenMapper {
+ private ArrayList functionBracePositions = new ArrayList();
+
+ /**
+ * Map of all replaced tokens
+ */
+ private ArrayList replacedTokens = new ArrayList();
+
+ /**
+ * Collection of Function nodes
+ */
+ private static ObjArray funcObjects = new ObjArray();
+
+ /**
+ * Map of each Function node and all the variables in its current function
+ * scope, other variables found while traversing the prototype chain and
+ * variables found in the top-level scope.
+ */
+ private static ArrayList functionVarMappings = new ArrayList();
+
+ public int functionNum = 0;
+
+ private int parentScope = 0;
+
+ private int lastTokenCount = 0;
+
+ /**
+ * Generate new compressed tokens
+ * <p>
+ *
+ * @param token
+ * value of the string token
+ * @param hasNewMapping
+ * boolean value indicating a new variable binding
+ * @return compressed token
+ */
+ private String getMappedToken(String token, boolean hasNewMapping) {
+ String newToken = null;
+ HashMap tokens = null;
+ String blank = new String("");
+ int localScope = functionBracePositions.size() - 1;
+
+ String oldToken = getPreviousTokenMapping(token, hasNewMapping);
+
+ if (!oldToken.equalsIgnoreCase(blank)) {
+ return oldToken;
+ } else if ((hasNewMapping || isInScopeChain(token))) {
+ lastTokenCount++;
+ newToken = new String("_" + Integer.toHexString(lastTokenCount));
+ if (newToken.length() >= token.length()) {
+ newToken = token;
+ }
+ if (hasNewMapping) {
+ tokens = (HashMap) replacedTokens.get(localScope);
+ } else {
+ tokens = (HashMap) replacedTokens.get(parentScope);
+ }
+
+ tokens.put(token, newToken);
+ return newToken;
+ }
+ return token;
+ }
+
+ /**
+ * Checks for variable names in prototype chain
+ * <p>
+ *
+ * @param token
+ * value of the string token
+ * @return boolean value indicating if the token is present in the chained
+ * scope
+ */
+ private boolean isInScopeChain(String token) {
+ int scope = functionBracePositions.size();
+ HashMap chainedScopeVars = (HashMap) functionVarMappings
+ .get(functionNum);
+ if (!chainedScopeVars.isEmpty()) {
+ for (int i = scope; i > 0; i--) {
+ if (chainedScopeVars.containsKey(new Integer(i))) {
+ parentScope = i - 1;
+ List temp = Arrays.asList((String[]) chainedScopeVars
+ .get(new Integer(i)));
+ if (temp.indexOf(token) != -1) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks previous token mapping
+ * <p>
+ *
+ * @param token
+ * value of the string token
+ * @param hasNewMapping
+ * boolean value indicating a new variable binding
+ * @return string value of the previous token or blank string
+ */
+ private String getPreviousTokenMapping(String token, boolean hasNewMapping) {
+ String result = new String("");
+ int scope = replacedTokens.size() - 1;
+
+ if (scope < 0) {
+ return result;
+ }
+
+ if (hasNewMapping) {
+ HashMap tokens = (HashMap) (replacedTokens.get(scope));
+ if (tokens.containsKey(token)) {
+ result = (String) tokens.get(token);
+ return result;
+ }
+ } else {
+ for (int i = scope; i > -1; i--) {
+ HashMap tokens = (HashMap) (replacedTokens.get(i));
+ if (tokens.containsKey(token)) {
+ result = (String) tokens.get(token);
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generate mappings for each Function node and parameters and variables
+ * names associated with it.
+ * <p>
+ *
+ * @param parseTree
+ * Mapping for each function node and corresponding parameters &
+ * variables names
+ */
+ private void collectFunctionMappings(ScriptOrFnNode parseTree) {
+ int level = -1;
+ collectFuncNodes(parseTree, level);
+ }
+
+ /**
+ * Recursive method to traverse all Function nodes
+ * <p>
+ *
+ * @param parseTree
+ * Mapping for each function node and corresponding parameters &
+ * variables names
+ * @param level
+ * scoping level
+ */
+ private static void collectFuncNodes(ScriptOrFnNode parseTree, int level) {
+ level++;
+ functionVarMappings.add(new HashMap());
+
+ HashMap bindingNames = (HashMap) functionVarMappings
+ .get(functionVarMappings.size() - 1);
+ bindingNames.put(new Integer(level), parseTree.getParamAndVarNames());
+ funcObjects.add(parseTree);
+
+ int nestedCount = parseTree.getFunctionCount();
+ for (int i = 0; i != nestedCount; ++i) {
+ collectFuncNodes(parseTree.getFunctionNode(i), level);
+ bindingNames = (HashMap) functionVarMappings
+ .get(functionVarMappings.size() - 1);
+ bindingNames.put(new Integer(level), parseTree
+ .getParamAndVarNames());
+ }
+ }
+
+ /**
+ * Compress the script
+ * <p>
+ *
+ * @param encodedSource
+ * encoded source string
+ * @param offset
+ * position within the encoded source
+ * @param asQuotedString
+ * boolean value indicating a quoted string
+ * @param sb
+ * String buffer reference
+ * @param prevToken
+ * Previous token in encoded source
+ * @param inArgsList
+ * boolean value indicating position inside arguments list
+ * @param currentLevel
+ * embeded function level
+ * @param parseTree
+ * Mapping of each function node and corresponding parameters &
+ * variables names
+ * @return compressed script
+ */
+ public int sourceCompress(String encodedSource, int offset,
+ boolean asQuotedString, StringBuffer sb, int prevToken,
+ boolean inArgsList, int currentLevel, ScriptOrFnNode parseTree) {
+
+ boolean hasNewMapping = false;
+
+ if (functionVarMappings.isEmpty())
+ collectFunctionMappings(parseTree);
+
+ int length = encodedSource.charAt(offset);
+ ++offset;
+ if ((0x8000 & length) != 0) {
+ length = ((0x7FFF & length) << 16) | encodedSource.charAt(offset);
+ ++offset;
+ }
+ if (sb != null) {
+ String str = encodedSource.substring(offset, offset + length);
+ String sourceStr = new String(str);
+ if ((prevToken == Token.VAR) || (inArgsList)) {
+ hasNewMapping = true;
+ }
+ if (((functionBracePositions.size() > 0) && (currentLevel >= (((Integer) functionBracePositions
+ .get(functionBracePositions.size() - 1)).intValue())))
+ || (inArgsList)) {
+ if (prevToken != Token.DOT) {
+ str = this.getMappedToken(str, hasNewMapping);
+ }
+ }
+ if ((!inArgsList) && (asQuotedString)) {
+ if ((prevToken == Token.LC) || (prevToken == Token.COMMA)) {
+ str = sourceStr;
+ }
+ }
+ if (!asQuotedString) {
+ sb.append(str);
+ } else {
+ sb.append('"');
+ sb.append(ScriptRuntime.escapeString(str));
+ sb.append('"');
+ }
+ }
+ return offset + length;
+ }
+
+ public void enterNestingLevel(int braceNesting) {
+ functionBracePositions.add(new Integer(braceNesting + 1));
+ replacedTokens.add(new HashMap());
+ }
+
+ public void leaveNestingLevel(int braceNesting) {
+ Integer bn = new Integer(braceNesting);
+
+ if ((functionBracePositions.contains(bn))
+ && (replacedTokens.size() > 0)) {
+ // remove our mappings now!
+ int scopedSize = replacedTokens.size();
+ replacedTokens.remove(scopedSize - 1);
+ functionBracePositions.remove(bn);
+ }
+ }
+}
+
+
public class Decompiler
{
/**
@@ -270,6 +533,512 @@
return new String(sourceBuffer, offset, sourceTop - offset);
}
+ private static TokenMapper tm = new TokenMapper();
+
+ /**
+ * Compress the script
+ * <p>
+ *
+ * @param encodedSource encoded source string
+ * @param flags Flags specifying format of decompilation output
+ * @param properties Decompilation properties
+ * @param parseTree Mapping for each function node and corresponding parameters & variables names
+ * @return compressed script
+ */
+ public static String compress(String encodedSource, int flags,
+ UintMap properties, ScriptOrFnNode parseTree){
+
+ int length = encodedSource.length();
+ if (length == 0) { return ""; }
+ int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
+ if (indent < 0) throw new IllegalArgumentException();
+ int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
+ if (indentGap < 0) throw new IllegalArgumentException();
+ int caseGap = properties.getInt(CASE_GAP_PROP, 2);
+ if (caseGap < 0) throw new IllegalArgumentException();
+ StringBuffer result = new StringBuffer();
+ boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
+ boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
+ // Spew tokens in source, for debugging.
+ // as TYPE number char
+ if (printSource) {
+ System.err.println("length:" + length);
+ for (int i = 0; i < length; ++i) {
+ // Note that tokenToName will fail unless Context.printTrees
+ // is true.
+ String tokenname = null;
+ if (Token.printNames) {
+ tokenname = Token.name(encodedSource.charAt(i));
+ }
+ if (tokenname == null) {
+ tokenname = "---";
+ }
+ String pad = tokenname.length() > 7
+ ? "\t"
+ : "\t\t";
+ System.err.println
+ (tokenname
+ + pad + (int)encodedSource.charAt(i)
+ + "\t'" + ScriptRuntime.escapeString
+ (encodedSource.substring(i, i+1))
+ + "'");
+ }
+ System.err.println();
+ }
+ int braceNesting = 0;
+ boolean afterFirstEOL = false;
+ int i = 0;
+ int prevToken = 0;
+ boolean primeFunctionNesting = false;
+ boolean inArgsList = false;
+ boolean primeInArgsList = false;
+ int topFunctionType;
+ if (encodedSource.charAt(i) == Token.SCRIPT) {
+ ++i;
+ topFunctionType = -1;
+ } else {
+ topFunctionType = encodedSource.charAt(i + 1);
+ }
+ if (!toSource) {
+ // add an initial newline to exactly match js.
+ // result.append('\n');
+ for (int j = 0; j < indent; j++){
+ // result.append(' ');
+ result.append("");
+ }
+ } else {
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
+ result.append('(');
+ }
+ }
+ while (i < length) {
+ if(i>0){
+ prevToken = encodedSource.charAt(i-1);
+ }
+ // System.out.println(Token.name(getNext(source, length, i)));
+ switch(encodedSource.charAt(i)) {
+ case Token.NAME:
+ case Token.REGEXP: // re-wrapped in '/'s in parser...
+ int jumpPos = getSourceStringEnd(encodedSource, i+1);
+ if(Token.OBJECTLIT == encodedSource.charAt(jumpPos)){
+ i = printSourceString(encodedSource, i + 1, false, result);
+ }else{
+ i = tm.sourceCompress( encodedSource, i + 1, false, result, prevToken,
+ inArgsList, braceNesting, parseTree);
+ }
+ continue;
+ case Token.STRING:
+ i = printSourceString(encodedSource, i + 1, true, result);
+ continue;
+ case Token.NUMBER:
+ i = printSourceNumber(encodedSource, i + 1, result);
+ continue;
+ case Token.TRUE:
+ result.append("true");
+ break;
+ case Token.FALSE:
+ result.append("false");
+ break;
+ case Token.NULL:
+ result.append("null");
+ break;
+ case Token.THIS:
+ result.append("this");
+ break;
+ case Token.FUNCTION:
+ ++i; // skip function type
+ tm.functionNum++;
+ primeInArgsList = true;
+ primeFunctionNesting = true;
+ result.append("function");
+ if (Token.LP != getNext(encodedSource, length, i)) {
+ result.append(' ');
+ }
+ break;
+ case FUNCTION_END:
+ // Do nothing
+ break;
+ case Token.COMMA:
+ result.append(",");
+ break;
+ case Token.LC:
+ ++braceNesting;
+ if (Token.EOL == getNext(encodedSource, length, i)){
+ indent += indentGap;
+ }
+ result.append('{');
+ // // result.append('\n');
+ break;
+ case Token.RC: {
+ tm.leaveNestingLevel(braceNesting);
+ --braceNesting;
+ /* don't print the closing RC if it closes the
+ * toplevel function and we're called from
+ * decompileFunctionBody.
+ */
+ if(justFunctionBody && braceNesting == 0){
+ break;
+ }
+ // // result.append('\n');
+ result.append('}');
+ // // result.append(' ');
+ switch (getNext(encodedSource, length, i)) {
+ case Token.EOL:
+ case FUNCTION_END:
+ indent -= indentGap;
+ break;
+ case Token.WHILE:
+ case Token.ELSE:
+ indent -= indentGap;
+ // result.append(' ');
+ result.append("");
+ break;
+ }
+ break;
+ }
+ case Token.LP:
+ if(primeInArgsList){
+ inArgsList = true;
+ primeInArgsList = false;
+ }
+ if(primeFunctionNesting){
+ tm.enterNestingLevel(braceNesting);
+ primeFunctionNesting = false;
+ }
+ result.append('(');
+ break;
+ case Token.RP:
+ if(inArgsList){
+ inArgsList = false;
+ }
+ result.append(')');
+ /*
+ if (Token.LC == getNext(source, length, i)){
+ result.append(' ');
+ }
+ */
+ break;
+ case Token.LB:
+ result.append('[');
+ break;
+ case Token.RB:
+ result.append(']');
+ break;
+ case Token.EOL: {
+ if (toSource) break;
+ boolean newLine = true;
+ if (!afterFirstEOL) {
+ afterFirstEOL = true;
+ if (justFunctionBody) {
+ /* throw away just added 'function name(...) {'
+ * and restore the original indent
+ */
+ result.setLength(0);
+ indent -= indentGap;
+ newLine = false;
+ }
+ }
+ if (newLine) {
+ result.append('\n');
+ }
+ /*
+ */
+ /* add indent if any tokens remain,
+ * less setback if next token is
+ * a label, case or default.
+ */
+ if (i + 1 < length) {
+ int less = 0;
+ int nextToken = encodedSource.charAt(i + 1);
+ if (nextToken == Token.CASE
+ || nextToken == Token.DEFAULT)
+ {
+ less = indentGap - caseGap;
+ } else if (nextToken == Token.RC) {
+ less = indentGap;
+ }
+ /* elaborate check against label... skip past a
+ * following inlined NAME and look for a COLON.
+ */
+ else if (nextToken == Token.NAME) {
+ int afterName = getSourceStringEnd(encodedSource, i + 2);
+ if (encodedSource.charAt(afterName) == Token.COLON)
+ less = indentGap;
+ }
+ for (; less < indent; less++){
+ // result.append(' ');
+ result.append("");
+ }
+ }
+ break;
+ }
+ case Token.DOT:
+ result.append('.');
+ break;
+ case Token.NEW:
+ result.append("new ");
+ break;
+ case Token.DELPROP:
+ result.append("delete ");
+ break;
+ case Token.IF:
+ result.append("if");
+ break;
+ case Token.ELSE:
+ result.append("else");
+ break;
+ case Token.FOR:
+ result.append("for");
+ break;
+ case Token.IN:
+ result.append(" in ");
+ break;
+ case Token.WITH:
+ result.append("with");
+ break;
+ case Token.WHILE:
+ result.append("while");
+ break;
+ case Token.DO:
+ result.append("do");
+ break;
+ case Token.TRY:
+ result.append("try");
+ break;
+ case Token.CATCH:
+ result.append("catch");
+ break;
+ case Token.FINALLY:
+ result.append("finally");
+ break;
+ case Token.THROW:
+ result.append("throw ");
+ break;
+ case Token.SWITCH:
+ result.append("switch");
+ break;
+ case Token.BREAK:
+ result.append("break");
+ if(Token.NAME == getNext(encodedSource, length, i)){
+ result.append(' ');
+ }
+ break;
+ case Token.CONTINUE:
+ result.append("continue");
+ if(Token.NAME == getNext(encodedSource, length, i)){
+ result.append(' ');
+ }
+ break;
+ case Token.CASE:
+ result.append("case ");
+ break;
+ case Token.DEFAULT:
+ result.append("default");
+ break;
+ case Token.RETURN:
+ result.append("return");
+ if(Token.SEMI != getNext(encodedSource, length, i)){
+ result.append(' ');
+ }
+ break;
+ case Token.VAR:
+ result.append("var ");
+ break;
+ case Token.SEMI:
+ result.append(';');
+ // result.append('\n');
+ /*
+ if (Token.EOL != getNext(source, length, i)) {
+ // separators in FOR
+ result.append(' ');
+ }
+ */
+ break;
+ case Token.ASSIGN:
+ result.append("=");
+ break;
+ case Token.ASSIGN_ADD:
+ result.append("+=");
+ break;
+ case Token.ASSIGN_SUB:
+ result.append("-=");
+ break;
+ case Token.ASSIGN_MUL:
+ result.append("*=");
+ break;
+ case Token.ASSIGN_DIV:
+ result.append("/=");
+ break;
+ case Token.ASSIGN_MOD:
+ result.append("%=");
+ break;
+ case Token.ASSIGN_BITOR:
+ result.append("|=");
+ break;
+ case Token.ASSIGN_BITXOR:
+ result.append("^=");
+ break;
+ case Token.ASSIGN_BITAND:
+ result.append("&=");
+ break;
+ case Token.ASSIGN_LSH:
+ result.append("<<=");
+ break;
+ case Token.ASSIGN_RSH:
+ result.append(">>=");
+ break;
+ case Token.ASSIGN_URSH:
+ result.append(">>>=");
+ break;
+ case Token.HOOK:
+ result.append("?");
+ break;
+ case Token.OBJECTLIT:
+ // pun OBJECTLIT to mean colon in objlit property
+ // initialization.
+ // This needs to be distinct from COLON in the general case
+ // to distinguish from the colon in a ternary... which needs
+ // different spacing.
+ result.append(':');
+ break;
+ case Token.COLON:
+ if (Token.EOL == getNext(encodedSource, length, i))
+ // it's the end of a label
+ result.append(':');
+ else
+ // it's the middle part of a ternary
+ result.append(":");
+ break;
+ case Token.OR:
+ result.append("||");
+ break;
+ case Token.AND:
+ result.append("&&");
+ break;
+ case Token.BITOR:
+ result.append("|");
+ break;
+ case Token.BITXOR:
+ result.append("^");
+ break;
+ case Token.BITAND:
+ result.append("&");
+ break;
+ case Token.SHEQ:
+ result.append("===");
+ break;
+ case Token.SHNE:
+ result.append("!==");
+ break;
+ case Token.EQ:
+ result.append("==");
+ break;
+ case Token.NE:
+ result.append("!=");
+ break;
+ case Token.LE:
+ result.append("<=");
+ break;
+ case Token.LT:
+ result.append("<");
+ break;
+ case Token.GE:
+ result.append(">=");
+ break;
+ case Token.GT:
+ result.append(">");
+ break;
+ case Token.INSTANCEOF:
+ // FIXME: does this really need leading space?
+ result.append(" instanceof ");
+ break;
+ case Token.LSH:
+ result.append("<<");
+ break;
+ case Token.RSH:
+ result.append(">>");
+ break;
+ case Token.URSH:
+ result.append(">>>");
+ break;
+ case Token.TYPEOF:
+ result.append("typeof ");
+ break;
+ case Token.VOID:
+ result.append("void ");
+ break;
+ case Token.NOT:
+ result.append('!');
+ break;
+ case Token.BITNOT:
+ result.append('~');
+ break;
+ case Token.POS:
+ result.append('+');
+ break;
+ case Token.NEG:
+ result.append('-');
+ break;
+ case Token.INC:
+ if(Token.ADD == prevToken){
+ result.append(' ');
+ }
+ result.append("++");
+ if(Token.ADD == getNext(encodedSource, length, i)){
+ result.append(' ');
+ }
+ break;
+ case Token.DEC:
+ if(Token.SUB == prevToken){
+ result.append(' ');
+ }
+ result.append("--");
+ if(Token.SUB == getNext(encodedSource, length, i)){
+ result.append(' ');
+ }
+ break;
+ case Token.ADD:
+ result.append("+");
+ break;
+ case Token.SUB:
+ result.append("-");
+ break;
+ case Token.MUL:
+ result.append("*");
+ break;
+ case Token.DIV:
+ result.append("/");
+ break;
+ case Token.MOD:
+ result.append("%");
+ break;
+ case Token.COLONCOLON:
+ result.append("::");
+ break;
+ case Token.DOTDOT:
+ result.append("..");
+ break;
+ case Token.XMLATTR:
+ result.append('@');
+ break;
+ default:
+ // If we don't know how to decompile it, raise an exception.
+ throw new RuntimeException();
+ }
+ ++i;
+ }
+ if (!toSource) {
+ // add that trailing newline if it's an outermost function.
+ // if (!justFunctionBody){
+ // result.append('\n');
+ // }
+ } else {
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
+ result.append(')');
+ }
+ }
+ return result.toString();
+ }
/**
* Decompile the source information associated with this js
* function/script back into a string. For the most part, this
Index: src/org/mozilla/javascript/NativeFunction.java
===================================================================
--- src/org/mozilla/javascript/NativeFunction.java.orig 2009-11-16 15:55:50.222561412 +0100
+++ src/org/mozilla/javascript/NativeFunction.java 2009-11-16 15:56:40.118560586 +0100
@@ -75,6 +75,27 @@
}
}
+ /**
+ * Compress the script.
+ * <p>
+ *
+ * @param parseTree Mapping for each function node and corresponding parameters & variables names
+ * @param indent How much to indent the decompiled result
+ * @param flags Flags specifying format of decompilation output
+ * @return compressed script
+ */
+ final String compress(ScriptOrFnNode parseTree, int indent, int flags)
+ {
+ String encodedSource = getEncodedSource();
+ if (encodedSource == null) {
+ return super.compress(indent, flags);
+ } else {
+ UintMap properties = new UintMap(1);
+ properties.put(Decompiler.INITIAL_INDENT_PROP, indent);
+ return Decompiler.compress(encodedSource, flags, properties, parseTree);
+ }
+ }
+
@Override
public int getLength()
{
Index: src/org/mozilla/javascript/TokenStream.java
===================================================================
--- src/org/mozilla/javascript/TokenStream.java.orig 2009-11-16 15:55:50.222561412 +0100
+++ src/org/mozilla/javascript/TokenStream.java 2009-11-16 15:56:40.138561046 +0100
@@ -68,9 +68,12 @@
private final static int
EOF_CHAR = -1;
+ public StringBuffer lastComment;
+
TokenStream(Parser parser, Reader sourceReader, String sourceString,
int lineno)
{
+ this.lastComment = new StringBuffer();
this.parser = parser;
this.lineno = lineno;
if (sourceReader != null) {
@@ -754,6 +757,8 @@
case '/':
// is it a // comment?
+ // FIXME: RAR: comment, need to set config to optionally keep
+ // instead of skipping!
if (matchChar('/')) {
skipLine();
continue retry;
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java 2009-11-16 15:56:40.194560334 +0100
@@ -0,0 +1,63 @@
+
+ package org.mozilla.javascript.tools.debugger.downloaded;
+ import java.awt.Component;
+
+import java.awt.event.*;
+import java.awt.AWTEvent;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.util.EventObject;
+import java.io.Serializable;
+
+public class AbstractCellEditor implements CellEditor {
+
+ protected EventListenerList listenerList = new EventListenerList();
+
+ public Object getCellEditorValue() { return null; }
+ public boolean isCellEditable(EventObject e) { return true; }
+ public boolean shouldSelectCell(EventObject anEvent) { return false; }
+ public boolean stopCellEditing() { return true; }
+ public void cancelCellEditing() {}
+
+ public void addCellEditorListener(CellEditorListener l) {
+ listenerList.add(CellEditorListener.class, l);
+ }
+
+ public void removeCellEditorListener(CellEditorListener l) {
+ listenerList.remove(CellEditorListener.class, l);
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type.
+ * @see EventListenerList
+ */
+ protected void fireEditingStopped() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==CellEditorListener.class) {
+ ((CellEditorListener)listeners[i+1]).editingStopped(new ChangeEvent(this));
+ }
+ }
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type.
+ * @see EventListenerList
+ */
+ protected void fireEditingCanceled() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==CellEditorListener.class) {
+ ((CellEditorListener)listeners[i+1]).editingCanceled(new ChangeEvent(this));
+ }
+ }
+ }
+}
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java 2009-11-16 15:56:40.210560494 +0100
@@ -0,0 +1,356 @@
+/*
+ * @(#)JTreeTable.java 1.2 98/10/27
+ *
+ * Copyright 1997, 1998 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ *
+ * This software is the confidential and proprietary information
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
+ * shall not disclose such Confidential Information and shall use
+ * it only in accordance with the terms of the license agreement
+ * you entered into with Sun.
+ */
+
+
+ package org.mozilla.javascript.tools.debugger.downloaded;
+ import javax.swing.*;
+
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+
+import java.awt.Dimension;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import java.awt.event.MouseEvent;
+
+import java.util.EventObject;
+
+/**
+ * This example shows how to create a simple JTreeTable component,
+ * by using a JTree as a renderer (and editor) for the cells in a
+ * particular column in the JTable.
+ *
+ * @version 1.2 10/27/98
+ *
+ * @author Philip Milne
+ * @author Scott Violet
+ */
+public class JTreeTable extends JTable {
+ /** A subclass of JTree. */
+ protected TreeTableCellRenderer tree;
+
+ public JTreeTable(TreeTableModel treeTableModel) {
+ super();
+
+ // Create the tree. It will be used as a renderer and editor.
+ tree = new TreeTableCellRenderer(treeTableModel);
+
+ // Install a tableModel representing the visible rows in the tree.
+ super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
+
+ // Force the JTable and JTree to share their row selection models.
+ ListToTreeSelectionModelWrapper selectionWrapper = new
+ ListToTreeSelectionModelWrapper();
+ tree.setSelectionModel(selectionWrapper);
+ setSelectionModel(selectionWrapper.getListSelectionModel());
+
+ // Install the tree editor renderer and editor.
+ setDefaultRenderer(TreeTableModel.class, tree);
+ setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
+
+ // No grid.
+ setShowGrid(false);
+
+ // No intercell spacing
+ setIntercellSpacing(new Dimension(0, 0));
+
+ // And update the height of the trees row to match that of
+ // the table.
+ if (tree.getRowHeight() < 1) {
+ // Metal looks better like this.
+ setRowHeight(18);
+ }
+ }
+
+ /**
+ * Overridden to message super and forward the method to the tree.
+ * Since the tree is not actually in the component hieachy it will
+ * never receive this unless we forward it in this manner.
+ */
+ public void updateUI() {
+ super.updateUI();
+ if(tree != null) {
+ tree.updateUI();
+ }
+ // Use the tree's default foreground and background colors in the
+ // table.
+ LookAndFeel.installColorsAndFont(this, "Tree.background",
+ "Tree.foreground", "Tree.font");
+ }
+
+ /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
+ * paint the editor. The UI currently uses different techniques to
+ * paint the renderers and editors and overriding setBounds() below
+ * is not the right thing to do for an editor. Returning -1 for the
+ * editing row in this case, ensures the editor is never painted.
+ */
+ public int getEditingRow() {
+ return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
+ editingRow;
+ }
+
+ /**
+ * Overridden to pass the new rowHeight to the tree.
+ */
+ public void setRowHeight(int rowHeight) {
+ super.setRowHeight(rowHeight);
+ if (tree != null && tree.getRowHeight() != rowHeight) {
+ tree.setRowHeight(getRowHeight());
+ }
+ }
+
+ /**
+ * Returns the tree that is being shared between the model.
+ */
+ public JTree getTree() {
+ return tree;
+ }
+
+ /**
+ * A TreeCellRenderer that displays a JTree.
+ */
+ public class TreeTableCellRenderer extends JTree implements
+ TableCellRenderer {
+ /** Last table/tree row asked to renderer. */
+ protected int visibleRow;
+
+ public TreeTableCellRenderer(TreeModel model) {
+ super(model);
+ }
+
+ /**
+ * updateUI is overridden to set the colors of the Tree's renderer
+ * to match that of the table.
+ */
+ public void updateUI() {
+ super.updateUI();
+ // Make the tree's cell renderer use the table's cell selection
+ // colors.
+ TreeCellRenderer tcr = getCellRenderer();
+ if (tcr instanceof DefaultTreeCellRenderer) {
+ DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
+ // For 1.1 uncomment this, 1.2 has a bug that will cause an
+ // exception to be thrown if the border selection color is
+ // null.
+ // dtcr.setBorderSelectionColor(null);
+ dtcr.setTextSelectionColor(UIManager.getColor
+ ("Table.selectionForeground"));
+ dtcr.setBackgroundSelectionColor(UIManager.getColor
+ ("Table.selectionBackground"));
+ }
+ }
+
+ /**
+ * Sets the row height of the tree, and forwards the row height to
+ * the table.
+ */
+ public void setRowHeight(int rowHeight) {
+ if (rowHeight > 0) {
+ super.setRowHeight(rowHeight);
+ if (JTreeTable.this != null &&
+ JTreeTable.this.getRowHeight() != rowHeight) {
+ JTreeTable.this.setRowHeight(getRowHeight());
+ }
+ }
+ }
+
+ /**
+ * This is overridden to set the height to match that of the JTable.
+ */
+ public void setBounds(int x, int y, int w, int h) {
+ super.setBounds(x, 0, w, JTreeTable.this.getHeight());
+ }
+
+ /**
+ * Sublcassed to translate the graphics such that the last visible
+ * row will be drawn at 0,0.
+ */
+ public void paint(Graphics g) {
+ g.translate(0, -visibleRow * getRowHeight());
+ super.paint(g);
+ }
+
+ /**
+ * TreeCellRenderer method. Overridden to update the visible row.
+ */
+ public Component getTableCellRendererComponent(JTable table,
+ Object value,
+ boolean isSelected,
+ boolean hasFocus,
+ int row, int column) {
+ if(isSelected)
+ setBackground(table.getSelectionBackground());
+ else
+ setBackground(table.getBackground());
+
+ visibleRow = row;
+ return this;
+ }
+ }
+
+
+ /**
+ * TreeTableCellEditor implementation. Component returned is the
+ * JTree.
+ */
+ public class TreeTableCellEditor extends AbstractCellEditor implements
+ TableCellEditor {
+ public Component getTableCellEditorComponent(JTable table,
+ Object value,
+ boolean isSelected,
+ int r, int c) {
+ return tree;
+ }
+
+ /**
+ * Overridden to return false, and if the event is a mouse event
+ * it is forwarded to the tree.<p>
+ * The behavior for this is debatable, and should really be offered
+ * as a property. By returning false, all keyboard actions are
+ * implemented in terms of the table. By returning true, the
+ * tree would get a chance to do something with the keyboard
+ * events. For the most part this is ok. But for certain keys,
+ * such as left/right, the tree will expand/collapse where as
+ * the table focus should really move to a different column. Page
+ * up/down should also be implemented in terms of the table.
+ * By returning false this also has the added benefit that clicking
+ * outside of the bounds of the tree node, but still in the tree
+ * column will select the row, whereas if this returned true
+ * that wouldn't be the case.
+ * <p>By returning false we are also enforcing the policy that
+ * the tree will never be editable (at least by a key sequence).
+ */
+ public boolean isCellEditable(EventObject e) {
+ if (e instanceof MouseEvent) {
+ for (int counter = getColumnCount() - 1; counter >= 0;
+ counter--) {
+ if (getColumnClass(counter) == TreeTableModel.class) {
+ MouseEvent me = (MouseEvent)e;
+ MouseEvent newME = new MouseEvent(tree, me.getID(),
+ me.getWhen(), me.getModifiers(),
+ me.getX() - getCellRect(0, counter, true).x,
+ me.getY(), me.getClickCount(),
+ me.isPopupTrigger());
+ tree.dispatchEvent(newME);
+ break;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+
+ /**
+ * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
+ * to listen for changes in the ListSelectionModel it maintains. Once
+ * a change in the ListSelectionModel happens, the paths are updated
+ * in the DefaultTreeSelectionModel.
+ */
+ public class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
+ /** Set to true when we are updating the ListSelectionModel. */
+ protected boolean updatingListSelectionModel;
+
+ public ListToTreeSelectionModelWrapper() {
+ super();
+ getListSelectionModel().addListSelectionListener
+ (createListSelectionListener());
+ }
+
+ /**
+ * Returns the list selection model. ListToTreeSelectionModelWrapper
+ * listens for changes to this model and updates the selected paths
+ * accordingly.
+ */
+ public ListSelectionModel getListSelectionModel() {
+ return listSelectionModel;
+ }
+
+ /**
+ * This is overridden to set <code>updatingListSelectionModel</code>
+ * and message super. This is the only place DefaultTreeSelectionModel
+ * alters the ListSelectionModel.
+ */
+ public void resetRowSelection() {
+ if(!updatingListSelectionModel) {
+ updatingListSelectionModel = true;
+ try {
+ super.resetRowSelection();
+ }
+ finally {
+ updatingListSelectionModel = false;
+ }
+ }
+ // Notice how we don't message super if
+ // updatingListSelectionModel is true. If
+ // updatingListSelectionModel is true, it implies the
+ // ListSelectionModel has already been updated and the
+ // paths are the only thing that needs to be updated.
+ }
+
+ /**
+ * Creates and returns an instance of ListSelectionHandler.
+ */
+ protected ListSelectionListener createListSelectionListener() {
+ return new ListSelectionHandler();
+ }
+
+ /**
+ * If <code>updatingListSelectionModel</code> is false, this will
+ * reset the selected paths from the selected rows in the list
+ * selection model.
+ */
+ protected void updateSelectedPathsFromSelectedRows() {
+ if(!updatingListSelectionModel) {
+ updatingListSelectionModel = true;
+ try {
+ // This is way expensive, ListSelectionModel needs an
+ // enumerator for iterating.
+ int min = listSelectionModel.getMinSelectionIndex();
+ int max = listSelectionModel.getMaxSelectionIndex();
+
+ clearSelection();
+ if(min != -1 && max != -1) {
+ for(int counter = min; counter <= max; counter++) {
+ if(listSelectionModel.isSelectedIndex(counter)) {
+ TreePath selPath = tree.getPathForRow
+ (counter);
+
+ if(selPath != null) {
+ addSelectionPath(selPath);
+ }
+ }
+ }
+ }
+ }
+ finally {
+ updatingListSelectionModel = false;
+ }
+ }
+ }
+
+ /**
+ * Class responsible for calling updateSelectedPathsFromSelectedRows
+ * when the selection of the list changse.
+ */
+ class ListSelectionHandler implements ListSelectionListener {
+ public void valueChanged(ListSelectionEvent e) {
+ updateSelectedPathsFromSelectedRows();
+ }
+ }
+ }
+}
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java 2009-11-16 15:56:40.226560347 +0100
@@ -0,0 +1,71 @@
+/*
+ * TreeTableModel.java
+ *
+ * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of Sun
+ * Microsystems, Inc. ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Sun.
+ *
+ * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
+ * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
+ * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
+ * THIS SOFTWARE OR ITS DERIVATIVES.
+ *
+ */
+
+
+ package org.mozilla.javascript.tools.debugger.downloaded;
+ import javax.swing.tree.TreeModel;
+
+
+/**
+ * TreeTableModel is the model used by a JTreeTable. It extends TreeModel
+ * to add methods for getting inforamtion about the set of columns each
+ * node in the TreeTableModel may have. Each column, like a column in
+ * a TableModel, has a name and a type associated with it. Each node in
+ * the TreeTableModel can return a value for each of the columns and
+ * set that value if isCellEditable() returns true.
+ *
+ * @author Philip Milne
+ * @author Scott Violet
+ */
+public interface TreeTableModel extends TreeModel
+{
+ /**
+ * Returns the number ofs availible column.
+ */
+ public int getColumnCount();
+
+ /**
+ * Returns the name for column number <code>column</code>.
+ */
+ public String getColumnName(int column);
+
+ /**
+ * Returns the type for column number <code>column</code>.
+ */
+ public Class getColumnClass(int column);
+
+ /**
+ * Returns the value to be displayed for node <code>node</code>,
+ * at column number <code>column</code>.
+ */
+ public Object getValueAt(Object node, int column);
+
+ /**
+ * Indicates whether the the value for node <code>node</code>,
+ * at column number <code>column</code> is editable.
+ */
+ public boolean isCellEditable(Object node, int column);
+
+ /**
+ * Sets the value for node <code>node</code>,
+ * at column number <code>column</code>.
+ */
+ public void setValueAt(Object aValue, Object node, int column);
+}
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java 2009-11-16 15:56:40.246560362 +0100
@@ -0,0 +1,128 @@
+/*
+ * @(#)TreeTableModelAdapter.java 1.2 98/10/27
+ *
+ * Copyright 1997, 1998 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ *
+ * This software is the confidential and proprietary information
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
+ * shall not disclose such Confidential Information and shall use
+ * it only in accordance with the terms of the license agreement
+ * you entered into with Sun.
+ */
+
+
+ package org.mozilla.javascript.tools.debugger.downloaded;
+ import javax.swing.JTree;
+
+import javax.swing.SwingUtilities;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.tree.TreePath;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeExpansionListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+
+/**
+ * This is a wrapper class takes a TreeTableModel and implements
+ * the table model interface. The implementation is trivial, with
+ * all of the event dispatching support provided by the superclass:
+ * the AbstractTableModel.
+ *
+ * @version 1.2 10/27/98
+ *
+ * @author Philip Milne
+ * @author Scott Violet
+ */
+public class TreeTableModelAdapter extends AbstractTableModel
+{
+ JTree tree;
+ TreeTableModel treeTableModel;
+
+ public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) {
+ this.tree = tree;
+ this.treeTableModel = treeTableModel;
+
+ tree.addTreeExpansionListener(new TreeExpansionListener() {
+ // Don't use fireTableRowsInserted() here; the selection model
+ // would get updated twice.
+ public void treeExpanded(TreeExpansionEvent event) {
+ fireTableDataChanged();
+ }
+ public void treeCollapsed(TreeExpansionEvent event) {
+ fireTableDataChanged();
+ }
+ });
+
+ // Install a TreeModelListener that can update the table when
+ // tree changes. We use delayedFireTableDataChanged as we can
+ // not be guaranteed the tree will have finished processing
+ // the event before us.
+ treeTableModel.addTreeModelListener(new TreeModelListener() {
+ public void treeNodesChanged(TreeModelEvent e) {
+ delayedFireTableDataChanged();
+ }
+
+ public void treeNodesInserted(TreeModelEvent e) {
+ delayedFireTableDataChanged();
+ }
+
+ public void treeNodesRemoved(TreeModelEvent e) {
+ delayedFireTableDataChanged();
+ }
+
+ public void treeStructureChanged(TreeModelEvent e) {
+ delayedFireTableDataChanged();
+ }
+ });
+ }
+
+ // Wrappers, implementing TableModel interface.
+
+ public int getColumnCount() {
+ return treeTableModel.getColumnCount();
+ }
+
+ public String getColumnName(int column) {
+ return treeTableModel.getColumnName(column);
+ }
+
+ public Class getColumnClass(int column) {
+ return treeTableModel.getColumnClass(column);
+ }
+
+ public int getRowCount() {
+ return tree.getRowCount();
+ }
+
+ protected Object nodeForRow(int row) {
+ TreePath treePath = tree.getPathForRow(row);
+ return treePath.getLastPathComponent();
+ }
+
+ public Object getValueAt(int row, int column) {
+ return treeTableModel.getValueAt(nodeForRow(row), column);
+ }
+
+ public boolean isCellEditable(int row, int column) {
+ return treeTableModel.isCellEditable(nodeForRow(row), column);
+ }
+
+ public void setValueAt(Object value, int row, int column) {
+ treeTableModel.setValueAt(value, nodeForRow(row), column);
+ }
+
+ /**
+ * Invokes fireTableDataChanged after all the pending events have been
+ * processed. SwingUtilities.invokeLater is used to handle this.
+ */
+ protected void delayedFireTableDataChanged() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ fireTableDataChanged();
+ }
+ });
+ }
+}
+
Index: toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
===================================================================
--- toolsrc/org/mozilla/javascript/tools/resources/Messages.properties.orig 2009-11-16 15:55:50.222561412 +0100
+++ toolsrc/org/mozilla/javascript/tools/resources/Messages.properties 2009-11-16 15:56:40.262560311 +0100
@@ -68,6 +68,8 @@
\ -opt [-1|0-9] Set optimization level.\n\
\ -f script-filename Execute script file, or "-" for interactive.\n\
\ -e script-source Evaluate inline script.\n\
+ \ -o output-filename Set the output filename.\n\
+ \ -c script-filename Set the script filename.\n\
\ -debug Generate debug code.\n\
\ -strict Enable strict mode warnings.\n\
\ -fatal-warnings Treat warnings as errors.\n\
Index: toolsrc/org/mozilla/javascript/tools/shell/Main.java
===================================================================
--- toolsrc/org/mozilla/javascript/tools/shell/Main.java.orig 2009-11-16 15:56:33.234061036 +0100
+++ toolsrc/org/mozilla/javascript/tools/shell/Main.java 2009-11-16 15:56:40.278560563 +0100
@@ -89,6 +89,9 @@
static private final int EXITCODE_RUNTIME_ERROR = 3;
static private final int EXITCODE_FILE_NOT_FOUND = 4;
static boolean processStdin = true;
+ static boolean outputCompressed = false;
+ static String outputFileName = "dojo.js.compressed.js";
+ static boolean isOutputFileSet = false;
static List<String> fileList = new ArrayList<String>();
private static SecurityProxy securityImpl;
@@ -296,6 +299,20 @@
shellContextFactory.call(iproxy);
continue;
}
+ if (arg.equals("-c")) {
+ outputCompressed = true;
+ continue;
+ }
+ if (arg.equals("-o") && ++i < args.length) {
+ if (args[i].startsWith("-") || args[i].length() == 0)
+ {
+ usageError = arg;
+ break goodUsage;
+ }
+ isOutputFileSet = true;
+ outputFileName = args[i];
+ continue;
+ }
if (arg.equals("-w")) {
errorReporter.setIsReportingWarnings(true);
continue;
@@ -462,10 +479,12 @@
String path, Object securityDomain)
{
Script script;
+ String cout = null;
+ String source = null;
if (path.endsWith(".class")) {
script = loadCompiledScript(cx, path, securityDomain);
} else {
- String source = (String)readFileOrUrl(path, true);
+ source = (String)readFileOrUrl(path, true);
if (source == null) {
exitCode = EXITCODE_FILE_NOT_FOUND;
return;
@@ -485,9 +504,58 @@
}
script = loadScriptFromSource(cx, source, path, 1, securityDomain);
}
- if (script != null) {
- evaluateScript(script, cx, scope);
- }
+ if ((script != null) && (source != null)) {
+ if (outputCompressed) {
+ cout = compressScript(cx, scope, script, source, path, 1,
+ securityDomain);
+ if (isOutputFileSet) {
+ try {
+ BufferedWriter out = new BufferedWriter(new FileWriter(
+ outputFileName));
+ out.write(cout);
+ out.close();
+ } catch (IOException ex) {
+ Context.reportError(ex.toString());
+ }
+ System.out.println("Compressed file stored in '" + outputFileName + "'");
+ } else {
+ global.getOut().println(cout);
+ }
+
+ }else{
+ evaluateScript(script, cx, scope);
+ }
+ }
+ }
+
+ public static String compressScript(Context cx, Scriptable scope, Script script, String source, String sourceName, int lineno, Object securityDomain)
+ {
+ String compressedSource = null;
+ try {
+ if (script != null) {
+ compressedSource = cx.compressReader(scope, script, source, sourceName,
+ lineno, securityDomain);
+ } else {
+ compressedSource = source;
+ }
+ } catch (WrappedException we) {
+ global.getErr().println(we.getWrappedException().toString());
+ we.printStackTrace();
+ } catch (EvaluatorException ee) {
+ // Already printed message.
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (RhinoException rex) {
+ errorReporter.reportException(rex);
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (VirtualMachineError ex) {
+ // Treat StackOverflow and OutOfMemory as runtime errors
+ ex.printStackTrace();
+ String msg = ToolErrorReporter.getMessage(
+ "msg.uncaughtJSException", ex.toString());
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ Context.reportError(msg);
+ }
+ return compressedSource;
}
public static Script loadScriptFromSource(Context cx, String scriptSource,