diff -u -r -N -x .svn -x '*.orig' -w ./src/build.xml ../rhino1_5R4_1/src/build.xml --- ./src/build.xml 2003-04-21 13:20:24.000000000 +0000 +++ ../rhino1_5R4_1/src/build.xml 2004-07-20 15:54:35.000000000 +0000 @@ -11,11 +11,12 @@ - + + diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/Context.java ../rhino1_5R4_1/src/org/mozilla/javascript/Context.java --- ./src/org/mozilla/javascript/Context.java 2003-04-21 13:20:24.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/Context.java 2004-07-20 15:54:33.000000000 +0000 @@ -47,15 +47,22 @@ package org.mozilla.javascript; -import java.beans.*; -import java.io.*; -import java.util.Enumeration; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.text.MessageFormat; import java.util.Hashtable; import java.util.Locale; import java.util.ResourceBundle; -import java.text.MessageFormat; -import java.lang.reflect.*; -import org.mozilla.javascript.debug.*; + +import org.mozilla.javascript.debug.DebugReader; +import org.mozilla.javascript.debug.Debugger; +import org.mozilla.javascript.tools.debugger.Main; /** * This class represents the runtime context of an executing script. @@ -104,6 +111,12 @@ ((ContextListener)array[i]).contextCreated(this); } } + if (JavaScriptExtensions.useRhinoDebugger) { + org.mozilla.javascript.tools.debugger.Main dbgr = (Main)JavaScriptExtensions.getRhinoDebugger(); + dbgr.contextCreated(this); + // ContextData contextData = new ContextData(); + // this.setDebugger(debugger,contextData); + } } /** @@ -186,6 +199,10 @@ ++cx.enterCount; + if (JavaScriptExtensions.trackContext) { + JavaScriptExtensions.trackContextEnter(cx,cx.enterCount); + } + Object[] listeners = contextListeners; if (listeners != null) { for (int i = listeners.length; i-- != 0;) { @@ -215,6 +232,11 @@ throw new RuntimeException ("Calling Context.exit without previous Context.enter"); } + + if (JavaScriptExtensions.trackContext) { + JavaScriptExtensions.trackContextExit(cx,cx.enterCount); + } + if (Context.check && cx.enterCount < 1) Context.codeBug(); --cx.enterCount; if (cx.enterCount == 0) { diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/Delegator.java ../rhino1_5R4_1/src/org/mozilla/javascript/Delegator.java --- ./src/org/mozilla/javascript/Delegator.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/Delegator.java 2004-08-01 16:24:49.000000000 +0000 @@ -16,7 +16,7 @@ * Copyright (C) 2000 Matthias Radestock. All Rights Reserved. * * Contributor(s): - * Redfig Ltd (http://www.redfig.com) + * Redfig Ltd (http://www.redfig.org) * LShift Ltd (http://www.lshift.net) * * Alternatively, the contents of this file may be used under the terms diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/FunctionObject.java ../rhino1_5R4_1/src/org/mozilla/javascript/FunctionObject.java --- ./src/org/mozilla/javascript/FunctionObject.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/FunctionObject.java 2004-08-31 12:58:02.000000000 +0000 @@ -495,6 +495,9 @@ invoker = master.createInvoker(cx, method, types); } try { + if (JavaScriptExtensions.joeysHook) { + // System.out.println("FunctionObject.doInvoke(): Calling " + invoker + ".invoke(" + thisObj + "," + args.length + ")"); + } return invoker.invoke(thisObj, args); } catch (Exception e) { throw new InvocationTargetException(e); diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/Interpreter.java ../rhino1_5R4_1/src/org/mozilla/javascript/Interpreter.java --- ./src/org/mozilla/javascript/Interpreter.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/Interpreter.java 2004-06-17 11:23:50.000000000 +0000 @@ -39,6 +39,8 @@ package org.mozilla.javascript; import java.io.*; +import java.util.List; +import java.util.Vector; import org.mozilla.javascript.debug.*; @@ -1602,6 +1604,38 @@ DebugFrame debuggerFrame = null; if (cx.debugger != null) { debuggerFrame = cx.debugger.getFrame(cx, idata); + } else { + if (JavaScriptExtensions.outputRhinoTrace && !JavaScriptExtensions.useRhinoDebugger) { + debuggerFrame = new DebugFrame() { + public void onLineChange(Context cx, int lineNumber) { + System.out.println("[trace] onLineChange: " + lineNumber); + } + public void handleCompilationDone(Context cx, DebuggableScript fnOrScript, String source) { + } + public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) { + return null; + } + public void onEnter(Context cx, Scriptable activation, Scriptable thisObj, Object[] args) { + System.out.println("[trace] Entering: " + cx.getClassName() + ":" + activation+"/"+thisObj + " with args " + listFromArray(args)); + } + public void onExceptionThrown(Context cx, Throwable ex) { + System.err.println("[trace] Exception was thrown: " + ex); + } + public void onExit(Context cx, boolean byThrow, Object resultOrException) { + System.out.println("[trace] Leaving : with result=" + resultOrException); + } + + public List listFromArray(Object[] array) { + Vector list = new Vector(); + // list.copyInto(array); + for (int i=0;i 0 && iCode[j] != 0) j--; + int i = getShort(iCode, j); + if (i >= 0 && i < strings.length) { + lhs=strings[i]; + throw NativeGlobal.typeError1( "msg.is.not.defined", ScriptRuntime.toString(lhs),scope ); + } + } stack[stackTop] = ScriptRuntime.getProp(lhs, name, scope); break; } diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/JavaScriptExtensions.java ../rhino1_5R4_1/src/org/mozilla/javascript/JavaScriptExtensions.java --- ./src/org/mozilla/javascript/JavaScriptExtensions.java 1970-01-01 00:00:00.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/JavaScriptExtensions.java 2004-08-01 16:24:49.000000000 +0000 @@ -0,0 +1,163 @@ +/* + * Created on 16-Jun-2004 + * + * Copyright 2004 (c) Multicom Products Limited + * + */ +package org.mozilla.javascript; + +import java.awt.ActiveEvent; +import java.io.StringWriter; + +import org.mozilla.javascript.debug.Debugger; +import org.mozilla.javascript.tools.debugger.Main; + +/** + * @author joey@multicom.co.uk + * + * This class contains booleans managing each of the features we have added to Rhino. + *

+ * If all options are turned off, then Rhino will run essentially unchanged. + *

+ * You can pick+mix the features you want, to approach compatibility with JavaScript1.5, or with Microsoft's JScript. + *

+ * If you use an IDE, you can track the implementation of each feature by searching for references to that boolean made from Rhino or HttpUnit. + *

+ * HttpUnit developers may choose to adopt any of these features permanently, simply by removing the conditional check on its option. + */ +public class JavaScriptExtensions { + + /** Start options **/ + + /** @maxAutoRefresh + * If <=0, does not affect redirects. + * If >0, autoRefreshes are only followed if their timeout <= maxAutoRefresh seconds. + */ + public static int maxAutoRefresh = 60; + + /** Options to control what I consider are bug fixes **/ + public static boolean selectBoxesWithSizeOneAreNotMultipleSelectBoxes = true; + public static boolean returnDomInstanceIfCloneUnavailable = true; + + /** Options to make Rhino more like the ECMA standard / JavaScript1.5 **/ + public static boolean returnUndefinedInsteadOfException = true; // Sometimes when an access fails it throws an Exception. This will return Undefined instead, which matches JS1.5 behaviour. + public static boolean controlObjectOptionArrayCanBeAccessedFromControl = true; // This allows "shortcut access" to selectBox[1] instead of JavaScript1's selectBox.options[1] + + /** Options to make Rhino more like Internet Explorer's JScript **/ + public static boolean commaMeansOrInLogicalExpressions = true; // Some sites try to use "," as if it was the boolean operator "||" + public static boolean allowSetLengthInSelectionFormControl = true; // Extension since JS1 - can be actually implemented in two ways: + public static boolean allowSetLengthInSelectionFormControlWithIEImplementation = true; // Means nothing if previous boolean not true. If this boolean is true, uses IE-like implementation, otherwise uses proper ECMA standard + // ECMA standard says setting the length only shortens the list array if length is reduced, and does nothing else. When length is read, it is dependent on the last element in the array. + // But some dodgy sites increment an array's length and then get length in order to add a new element at the end. To match this implementation, we need to actually increase the array's length (and populate with null's/Invalid's). + + /** Tools for debugging. **/ + public static boolean catchJavaScriptErrors = true; // If there are errors whilst running (eg. stack-overflow exception when flybe's "," is not parsed correctly), this catches the Error within than execution, and lets Rhino continue. + public static boolean outputRhinoTrace = false; // Text output, intended as a trace, but not very informative at the moment. Uses a minimalist DebugFrame implementation. + public static boolean useRhinoDebugger = false; // Tries to popup the Rhino Swing debugger. (Overrides previous if true.) + + /** Developer: Debugging Threads/Context: **/ + public static boolean trackContext = true; + + /** For things I haven't otherwise named/documented. Becuase it's better to reference them here than not to reference them. **/ + public static boolean joeysHook = true; /** This actually serves same purpose as temporaryDebug, for the moment. **/ + public static boolean temporaryDebug = true; /** Things linked to this boolean are for debugging purposes, and once issues are resolved, can be removed. **/ + /** Note these booleans, and more, may be referenced from HttpUnit. **/ + + /** End options **/ + + /** Start implementation **/ + + public static Debugger debugger = null; + + public static void registerDebugger(Debugger _debugger) { + debugger = _debugger; + Main main = (Main)debugger; + // main.setBreakOnEnter(true); // The Javascript just flies past without this! + } + + static final Object theLock = new Object(); + + public static Debugger getRhinoDebugger() { + synchronized (theLock) { // To avoid ever creating two Debuggers; will block until first is created, then it won't try to create a second instance. + if (debugger == null) { + System.err.println("Creating new Debugger..."); + java.io.InputStream in = System.in; + java.io.PrintStream out = System.out; + java.io.PrintStream err = System.err; + new Thread () { + public void run() { + org.mozilla.javascript.tools.debugger.Main.main(new String[0]); + } + }.start(); + while (debugger == null) { + System.err.println("Waiting for debugger to initialise and register..."); + try { Thread.sleep(1000); } + catch (Exception e) { } + } + System.setIn(in); + System.setOut(out); + System.setErr(err); + System.err.println("OK debugger is ready!"); + } + } + return debugger; + } + + static java.util.Map activeContexts = new java.util.HashMap(); + public static void trackContextEnter(Context cx, int enterCount) { + activeContexts.put(cx+"#"+enterCount,getStackTrace()+" in "+Thread.currentThread()); + } + public static void trackContextExit(Context cx, int enterCount) { + activeContexts.remove(cx+"#"+enterCount); + } + public static void debugContexts() { + System.out.println("There are " + activeContexts.keySet().size() + " active Contexts."); + /* + java.util.Iterator i = activeContexts.keySet().iterator(); + while (i.hasNext()) { + Object key = i.next(); + System.out.println("Context " + key + " was entered at:\n" + activeContexts.get(key)); + } + */ + } + + public static void warn(Throwable e) { + e.printStackTrace(System.err); + } + public static String getStackTrace(Throwable e) { + java.io.StringWriter tmp = new StringWriter(); + e.printStackTrace(new java.io.PrintWriter(tmp)); + return tmp.toString(); + } + public static String getStackTrace() { + // java.io.StringWriter tmp = new StringWriter(); + try { + throw new Exception("dummy"); + } catch (Exception e) { + // e.printStackTrace(new java.io.PrintWriter(tmp)); + return getStackTrace(e); + } + // return tmp.toString(); + } + /** May still need some work. */ + public static String getCurrentMethod() { + String stackTrace = getStackTrace(); + // drop first line + int i = stackTrace.indexOf("\n"); + if (i>=0) { + stackTrace = stackTrace.substring(i); + } + // take second (now first) line + i = stackTrace.indexOf("\n"); + if (i>=0) { + stackTrace = stackTrace.substring(0,i); + } + // + stackTrace = stackTrace.trim(); + if (stackTrace.startsWith("at ")) { + stackTrace = stackTrace.substring(3).trim(); + } + return stackTrace; + } + +} diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/Parser.java ../rhino1_5R4_1/src/org/mozilla/javascript/Parser.java --- ./src/org/mozilla/javascript/Parser.java 2003-04-21 13:20:24.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/Parser.java 2004-07-08 15:33:53.000000000 +0000 @@ -36,6 +36,7 @@ package org.mozilla.javascript; +import java.io.BufferedReader; import java.io.IOException; /** @@ -943,7 +944,42 @@ throws IOException, JavaScriptException { Object pn = andExpr(ts, inForInit); - if (ts.matchToken(ts.OR)) { + + // A very dodgy hack to check whether we are parsing an argument list or a general expression. + // This changes what "," means, because at the top-level of an argument list it of course must mean "argument separator", + // but in logical expressions, IE interpret the "," as an OR operator. + // CONSIDER: have we dealt with ","s in arrays?! eg. "var mylist = [ true, false, true ];" + // If the parser comes through here whilst parsing an array, we will probably give it back one big logical expression! + // What other situations make use of ","s? + // What's a good way to determine whether the current context means ","s act specially, or they are free to act as ORs? + // I don't think grepping the stacktrace is a good plan, but it works for me for the moment. + + // OK whilst creating a "new Array(...)", the parser does think of it an an argumentList, so that's ok. + // Still to test... Can JS create arrays like "[ 1, 2, 3 ]" + // Where else can we find ','s?! + + // Parser.condition is a good sign that your in in an "if ()" clause, but what about "result = ( 1==2 , 2<1 );" ? + String stackTrace = JavaScriptExtensions.getStackTrace(); + // System.out.println("##### Checking new stack trace:"); // \n" + stackTrace); + // System.err.println("## Function#=" + functionNumber); + java.io.BufferedReader read = new java.io.BufferedReader(new java.io.StringReader(stackTrace)); + boolean inArgList = false; + for (int i=0;i<8;i++) { + String line = read.readLine(); + // System.err.println("## Checking: " + line); + if (line.indexOf("Parser.argumentList(") >= 0) { + inArgList = true; + //System.err.println("### argumentList found at line " + i); + break; + } + } + //System.err.println("Decided inArgList = " + inArgList); + //inArgList = false; // because it doesn't work! + //if (inArgList) { + //System.out.println("Not interpreting ',' as '||' since we are inside an argument list."); + //} + + if (ts.matchToken(ts.OR) || (JavaScriptExtensions.commaMeansOrInLogicalExpressions && !inArgList && ts.matchToken(ts.COMMA))) { // the matchToken had to come last otherwise it would be wasted if one of the other conditions decides /not/ to recognise the comma as an "or" sourceAdd((char)ts.OR); pn = nf.createBinary(ts.OR, pn, orExpr(ts, inForInit)); } diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/ScriptRuntime.java ../rhino1_5R4_1/src/org/mozilla/javascript/ScriptRuntime.java --- ./src/org/mozilla/javascript/ScriptRuntime.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/ScriptRuntime.java 2004-07-08 15:32:31.000000000 +0000 @@ -1073,11 +1073,15 @@ return result; obj = obj.getParentScope(); } + if (JavaScriptExtensions.returnUndefinedInsteadOfException) { + return Undefined.instance; + } else { throw NativeGlobal.constructError (Context.getContext(), "ReferenceError", ScriptRuntime.getMessage1("msg.is.not.defined", id.toString()), scopeChain); } + } /** * Returns the object in the scope chain that has a given property. diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/ScriptableObject.java ../rhino1_5R4_1/src/org/mozilla/javascript/ScriptableObject.java --- ./src/org/mozilla/javascript/ScriptableObject.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/ScriptableObject.java 2004-07-08 11:00:26.000000000 +0000 @@ -1425,6 +1425,22 @@ break; obj = obj.getPrototype(); } while (obj != null); + if (result == Scriptable.NOT_FOUND && JavaScriptExtensions.controlObjectOptionArrayCanBeAccessedFromControl) { + // If we are a Control with sub-options, we should return the indexed option. + obj = start; + if (obj.getClassName().equals("Control")) { + Object options = obj.get("options",obj); + if (options instanceof Scriptable) { + obj = (Scriptable)options; + do { + result = obj.get(index, start); + if (result != Scriptable.NOT_FOUND) + break; + obj = obj.getPrototype(); + } while (obj != null); + } + } + } return result; } diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/Synchronizer.java ../rhino1_5R4_1/src/org/mozilla/javascript/Synchronizer.java --- ./src/org/mozilla/javascript/Synchronizer.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/Synchronizer.java 2004-08-01 16:24:49.000000000 +0000 @@ -16,7 +16,7 @@ * Copyright (C) 2000 Matthias Radestock. All Rights Reserved. * * Contributor(s): - * Redfig Ltd (http://www.redfig.com) + * Redfig Ltd (http://www.redfig.org) * LShift Ltd (http://www.lshift.net) * * Alternatively, the contents of this file may be used under the terms diff -u -r -N -x .svn -x '*.orig' -w ./src/org/mozilla/javascript/optimizer/Codegen.java ../rhino1_5R4_1/src/org/mozilla/javascript/optimizer/Codegen.java --- ./src/org/mozilla/javascript/optimizer/Codegen.java 2003-04-21 13:20:22.000000000 +0000 +++ ../rhino1_5R4_1/src/org/mozilla/javascript/optimizer/Codegen.java 2004-06-23 17:02:39.000000000 +0000 @@ -219,11 +219,15 @@ void addScriptRuntimeInvoke(String methodName, String parameterSignature, String resultSignature) { + try { classFile.add(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", methodName, parameterSignature, resultSignature); + } catch (Throwable e) { + e.printStackTrace(System.err); + } } void addOptRuntimeInvoke(String methodName, String parameterSignature, String resultSignature)