Sophie

Sophie

distrib > Mandriva > 2009.0 > i586 > by-pkgid > 8c607662279c4bb7f2f80d21ca9924bf > files > 1

rhino-1.7-0.0.2.1mdv2009.0.src.rpm

diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/BaseFunction.java rhino1_6R4/src/org/mozilla/javascript/BaseFunction.java
--- rhino/src/org/mozilla/javascript/BaseFunction.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/src/org/mozilla/javascript/BaseFunction.java	2006-09-27 17:03:18.000000000 -0400
@@ -373,6 +373,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; }
diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/BaseFunction.java.rej rhino1_6R4/src/org/mozilla/javascript/BaseFunction.java.rej
--- rhino/src/org/mozilla/javascript/BaseFunction.java.rej	1969-12-31 19:00:00.000000000 -0500
+++ rhino1_6R4/src/org/mozilla/javascript/BaseFunction.java.rej	2006-09-27 17:08:59.000000000 -0400
@@ -0,0 +1,37 @@
+***************
+*** 373,378 ****
+          return sb.toString();
+      }
+  
+      public int getArity() { return 0; }
+  
+      public int getLength() { return 0; }
+--- 373,400 ----
+          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; }
diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/Context.java rhino1_6R4/src/org/mozilla/javascript/Context.java
--- rhino/src/org/mozilla/javascript/Context.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/src/org/mozilla/javascript/Context.java	2006-09-27 17:03:18.000000000 -0400
@@ -1178,6 +1178,33 @@
         }
     }
 
+        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>
@@ -1361,6 +1388,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
@@ -2240,7 +2288,6 @@
                 sourceReader = null;
             }
         }
-
         Parser p = new Parser(compilerEnv, compilationErrorReporter);
         if (returnFunction) {
             p.calledByCompileFunction = true;
@@ -2251,6 +2298,7 @@
         } else {
             tree = p.parse(sourceReader, sourceName, lineno);
         }
+        
         if (returnFunction) {
             if (!(tree.getFunctionCount() == 1
                   && tree.getFirstChild() != null
diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/Decompiler.java rhino1_6R4/src/org/mozilla/javascript/Decompiler.java
--- rhino/src/org/mozilla/javascript/Decompiler.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/src/org/mozilla/javascript/Decompiler.java	2006-09-27 17:03:18.000000000 -0400
@@ -37,6 +37,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
@@ -70,6 +75,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
 {
     /**
@@ -266,6 +529,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
diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/NativeFunction.java rhino1_6R4/src/org/mozilla/javascript/NativeFunction.java
--- rhino/src/org/mozilla/javascript/NativeFunction.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/src/org/mozilla/javascript/NativeFunction.java	2006-09-27 17:03:18.000000000 -0400
@@ -70,6 +70,26 @@
         }
     }
 
+    /**
+     * 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);
+        }
+    }
     public int getLength()
     {
         int paramCount = getParamCount();
diff -Naur -x '*.jar' rhino/src/org/mozilla/javascript/TokenStream.java rhino1_6R4/src/org/mozilla/javascript/TokenStream.java
--- rhino/src/org/mozilla/javascript/TokenStream.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/src/org/mozilla/javascript/TokenStream.java	2006-09-27 17:03:18.000000000 -0400
@@ -64,9 +64,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) {
@@ -736,6 +739,8 @@
 
             case '/':
                 // is it a // comment?
+            	// FIXME: RAR: comment, need to set config to optionally keep
+            	// instead of skipping!
                 if (matchChar('/')) {
                     skipLine();
                     continue retry;
diff -Naur -x '*.jar' rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java
--- rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java	1969-12-31 19:00:00.000000000 -0500
+++ rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java	2006-09-27 17:04:27.000000000 -0400
@@ -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));
+	    }	       
+	}
+    }
+}
diff -Naur -x '*.jar' rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java
--- rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java	1969-12-31 19:00:00.000000000 -0500
+++ rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java	2006-09-27 17:04:27.000000000 -0400
@@ -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();
+	    }
+	}
+    }
+}
diff -Naur -x '*.jar' rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java
--- rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java	1969-12-31 19:00:00.000000000 -0500
+++ rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java	2006-09-27 17:04:27.000000000 -0400
@@ -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();
+	    }
+	});
+    }
+}
+
diff -Naur -x '*.jar' rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java
--- rhino/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java	1969-12-31 19:00:00.000000000 -0500
+++ rhino1_6R4/toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java	2006-09-27 17:04:27.000000000 -0400
@@ -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);
+}
diff -Naur -x '*.jar' rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java rhino1_6R4/toolsrc/org/mozilla/javascript/tools/shell/Main.java
--- rhino/toolsrc/org/mozilla/javascript/tools/shell/Main.java	2006-09-09 13:14:10.000000000 -0400
+++ rhino1_6R4/toolsrc/org/mozilla/javascript/tools/shell/Main.java	2006-09-27 17:03:18.000000000 -0400
@@ -66,6 +66,11 @@
     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 Vector fileList = new Vector(5);
     private static SecurityProxy securityImpl;
 
@@ -260,6 +265,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;
@@ -395,10 +413,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;
@@ -418,9 +438,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,
--- rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties.orig	2008-01-11 09:48:28.000000000 +0000
+++ rhino1_7R1/toolsrc/org/mozilla/javascript/tools/resources/Messages.properties	2008-01-11 20:00:53.000000000 +0000
@@ -65,6 +65,8 @@
     \    -opt [-1|0-9]      Set optimization level.\n\
     \    -f script-filename Execute script file.\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.