+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation. Portions created by Netscape are\r
+ * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ *\r
+ * Patrick Beard\r
+ * Norris Boyd\r
+ * Igor Bukanov\r
+ * Brendan Eich\r
+ * Roger Lawrence\r
+ * Mike McCabe\r
+ * Ian D. Stewart\r
+ * Andi Vajda\r
+ * Andrew Wason\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+// API class\r
+\r
+package org.mozilla.javascript;\r
+\r
+import java.beans.*;\r
+import java.io.*;\r
+import java.util.Vector;\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Locale;\r
+import java.util.ResourceBundle;\r
+import java.util.ListResourceBundle;\r
+import java.text.MessageFormat;\r
+import java.lang.reflect.*;\r
+import org.mozilla.javascript.debug.*;\r
+\r
+/**\r
+ * This class represents the runtime context of an executing script.\r
+ *\r
+ * Before executing a script, an instance of Context must be created\r
+ * and associated with the thread that will be executing the script.\r
+ * The Context will be used to store information about the executing\r
+ * of the script such as the call stack. Contexts are associated with\r
+ * the current thread using the <a href="#enter()">enter()</a> method.<p>\r
+ *\r
+ * The behavior of the execution engine may be altered through methods\r
+ * such as <a href="#setLanguageVersion>setLanguageVersion</a> and\r
+ * <a href="#setErrorReporter>setErrorReporter</a>.<p>\r
+ *\r
+ * Different forms of script execution are supported. Scripts may be\r
+ * evaluated from the source directly, or first compiled and then later\r
+ * executed. Interactive execution is also supported.<p>\r
+ *\r
+ * Some aspects of script execution, such as type conversions and\r
+ * object creation, may be accessed directly through methods of\r
+ * Context.\r
+ *\r
+ * @see Scriptable\r
+ * @author Norris Boyd\r
+ * @author Brendan Eich\r
+ */\r
+\r
+public class Context {\r
+ public static final String languageVersionProperty = "language version";\r
+ public static final String errorReporterProperty = "error reporter";\r
+ \r
+ /**\r
+ * Create a new Context.\r
+ *\r
+ * Note that the Context must be associated with a thread before\r
+ * it can be used to execute a script.\r
+ *\r
+ * @see org.mozilla.javascript.Context#enter\r
+ */\r
+ public Context() {\r
+ init();\r
+ }\r
+ \r
+ /**\r
+ * Create a new context with the associated security support.\r
+ * \r
+ * @param securitySupport an encapsulation of the functionality \r
+ * needed to support security for scripts.\r
+ * @see org.mozilla.javascript.SecuritySupport\r
+ */\r
+ public Context(SecuritySupport securitySupport) {\r
+ this.securitySupport = securitySupport;\r
+ init();\r
+ }\r
+ \r
+ private void init() {\r
+ setLanguageVersion(VERSION_DEFAULT);\r
+ optimizationLevel = codegenClass != null ? 0 : -1;\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ((ContextListener)array[i]).contextCreated(this);\r
+ }\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Get a context associated with the current thread, creating\r
+ * one if need be.\r
+ *\r
+ * The Context stores the execution state of the JavaScript\r
+ * engine, so it is required that the context be entered\r
+ * before execution may begin. Once a thread has entered\r
+ * a Context, then getCurrentContext() may be called to find\r
+ * the context that is associated with the current thread.\r
+ * <p>\r
+ * Calling <code>enter()</code> will\r
+ * return either the Context currently associated with the\r
+ * thread, or will create a new context and associate it \r
+ * with the current thread. Each call to <code>enter()</code>\r
+ * must have a matching call to <code>exit()</code>. For example,\r
+ * <pre>\r
+ * Context cx = Context.enter();\r
+ * ...\r
+ * cx.evaluateString(...);\r
+ * Context.exit();\r
+ * </pre>\r
+ * @return a Context associated with the current thread\r
+ * @see org.mozilla.javascript.Context#getCurrentContext\r
+ * @see org.mozilla.javascript.Context#exit\r
+ */\r
+ public static Context enter() {\r
+ return enter(null);\r
+ }\r
+ \r
+ /**\r
+ * Get a Context associated with the current thread, using\r
+ * the given Context if need be.\r
+ * <p>\r
+ * The same as <code>enter()</code> except that <code>cx</code>\r
+ * is associated with the current thread and returned if \r
+ * the current thread has no associated context and <code>cx</code>\r
+ * is not associated with any other thread.\r
+ * @param cx a Context to associate with the thread if possible\r
+ * @return a Context associated with the current thread\r
+ */\r
+ public static Context enter(Context cx) {\r
+ // There's some duplication of code in this method to avoid\r
+ // unnecessary synchronizations.\r
+ Thread t = Thread.currentThread();\r
+ Context current = (Context) threadContexts.get(t);\r
+ if (current != null) {\r
+ synchronized (current) {\r
+ current.enterCount++;\r
+ }\r
+ }\r
+ else if (cx != null) {\r
+ synchronized (cx) {\r
+ if (cx.currentThread == null) {\r
+ cx.currentThread = t;\r
+ threadContexts.put(t, cx);\r
+ cx.enterCount++;\r
+ }\r
+ }\r
+ current = cx;\r
+ }\r
+ else {\r
+ current = new Context();\r
+ current.currentThread = t;\r
+ threadContexts.put(t, current);\r
+ current.enterCount = 1;\r
+ }\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ((ContextListener)array[i]).contextEntered(current);\r
+ }\r
+ }\r
+ return current;\r
+ }\r
+ \r
+ /**\r
+ * Exit a block of code requiring a Context.\r
+ *\r
+ * Calling <code>exit()</code> will remove the association between\r
+ * the current thread and a Context if the prior call to \r
+ * <code>enter()</code> on this thread newly associated a Context \r
+ * with this thread.\r
+ * Once the current thread no longer has an associated Context,\r
+ * it cannot be used to execute JavaScript until it is again associated\r
+ * with a Context.\r
+ *\r
+ * @see org.mozilla.javascript.Context#enter\r
+ */\r
+ public static void exit() {\r
+ Context cx = getCurrentContext();\r
+ boolean released = false;\r
+ if (cx != null) {\r
+ synchronized (cx) {\r
+ if (--cx.enterCount == 0) {\r
+ threadContexts.remove(cx.currentThread);\r
+ cx.currentThread = null;\r
+ released = true;\r
+ }\r
+ }\r
+ Object[] array = contextListeners;\r
+ if (array != null) {\r
+ for (int i = array.length; i-- != 0;) {\r
+ ContextListener l = (ContextListener)array[i];\r
+ l.contextExited(cx);\r
+ if (released) { l.contextReleased(cx); }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the current Context.\r
+ *\r
+ * The current Context is per-thread; this method looks up\r
+ * the Context associated with the current thread. <p>\r
+ *\r
+ * @return the Context associated with the current thread, or\r
+ * null if no context is associated with the current \r
+ * thread.\r
+ * @see org.mozilla.javascript.Context#enter\r
+ * @see org.mozilla.javascript.Context#exit\r
+ */\r
+ public static Context getCurrentContext() {\r
+ Thread t = Thread.currentThread();\r
+ return (Context) threadContexts.get(t);\r
+ }\r
+ \r
+ public static Context getContextForThread(Thread t) {\r
+ Context ret = (Context) threadContexts.get(t);\r
+ return ret == null ? Context.enter() : ret;\r
+ }\r
+ \r
+ /**\r
+ * Language versions\r
+ *\r
+ * All integral values are reserved for future version numbers.\r
+ */\r
+\r
+ /**\r
+ * The unknown version.\r
+ */\r
+ public static final int VERSION_UNKNOWN = -1;\r
+\r
+ /**\r
+ * The default version.\r
+ */\r
+ public static final int VERSION_DEFAULT = 0;\r
+\r
+ /**\r
+ * JavaScript 1.0\r
+ */\r
+ public static final int VERSION_1_0 = 100;\r
+\r
+ /**\r
+ * JavaScript 1.1\r
+ */\r
+ public static final int VERSION_1_1 = 110;\r
+\r
+ /**\r
+ * JavaScript 1.2\r
+ */\r
+ public static final int VERSION_1_2 = 120;\r
+\r
+ /**\r
+ * JavaScript 1.3\r
+ */\r
+ public static final int VERSION_1_3 = 130;\r
+\r
+ /**\r
+ * JavaScript 1.4\r
+ */\r
+ public static final int VERSION_1_4 = 140;\r
+\r
+ /**\r
+ * JavaScript 1.5\r
+ */\r
+ public static final int VERSION_1_5 = 150;\r
+\r
+ /**\r
+ * Get the current language version.\r
+ * <p>\r
+ * The language version number affects JavaScript semantics as detailed\r
+ * in the overview documentation.\r
+ *\r
+ * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.\r
+ */\r
+ public int getLanguageVersion() {\r
+ return version;\r
+ }\r
+\r
+ /**\r
+ * Set the language version.\r
+ *\r
+ * <p>\r
+ * Setting the language version will affect functions and scripts compiled\r
+ * subsequently. See the overview documentation for version-specific\r
+ * behavior.\r
+ *\r
+ * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.\r
+ */\r
+ public void setLanguageVersion(int version) {\r
+ Object[] array = listeners;\r
+ if (array != null && version != this.version) {\r
+ firePropertyChangeImpl(array, languageVersionProperty,\r
+ new Integer(this.version), \r
+ new Integer(version));\r
+ }\r
+ this.version = version;\r
+ }\r
+\r
+ /**\r
+ * Get the implementation version.\r
+ *\r
+ * <p>\r
+ * The implementation version is of the form \r
+ * <pre>\r
+ * "<i>name langVer</i> <code>release</code> <i>relNum date</i>"\r
+ * </pre>\r
+ * where <i>name</i> is the name of the product, <i>langVer</i> is \r
+ * the language version, <i>relNum</i> is the release number, and \r
+ * <i>date</i> is the release date for that specific \r
+ * release in the form "yyyy mm dd". \r
+ *\r
+ * @return a string that encodes the product, language version, release \r
+ * number, and date.\r
+ */\r
+ public String getImplementationVersion() {\r
+ return "Rhino 1.5 release 2 2001 07 27";\r
+ }\r
+\r
+ /**\r
+ * Get the current error reporter.\r
+ *\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public ErrorReporter getErrorReporter() {\r
+ if (errorReporter == null) {\r
+ errorReporter = new DefaultErrorReporter();\r
+ }\r
+ return errorReporter;\r
+ }\r
+\r
+ /**\r
+ * Change the current error reporter.\r
+ *\r
+ * @return the previous error reporter\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public ErrorReporter setErrorReporter(ErrorReporter reporter) {\r
+ ErrorReporter result = errorReporter;\r
+ Object[] array = listeners;\r
+ if (array != null && errorReporter != reporter) {\r
+ firePropertyChangeImpl(array, errorReporterProperty,\r
+ errorReporter, reporter);\r
+ }\r
+ errorReporter = reporter;\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Get the current locale. Returns the default locale if none has\r
+ * been set.\r
+ *\r
+ * @see java.util.Locale\r
+ */\r
+\r
+ public Locale getLocale() {\r
+ if (locale == null)\r
+ locale = Locale.getDefault();\r
+ return locale;\r
+ }\r
+\r
+ /**\r
+ * Set the current locale.\r
+ *\r
+ * @see java.util.Locale\r
+ */\r
+ public Locale setLocale(Locale loc) {\r
+ Locale result = locale;\r
+ locale = loc;\r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * Register an object to receive notifications when a bound property\r
+ * has changed\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @param listener the listener\r
+ */\r
+ public void addPropertyChangeListener(PropertyChangeListener listener) {\r
+ synchronized (this) {\r
+ listeners = ListenerArray.add(listeners, listener);\r
+ } \r
+ }\r
+ \r
+ /**\r
+ * Remove an object from the list of objects registered to receive \r
+ * notification of changes to a bounded property\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @param listener the listener\r
+ */\r
+ public void removePropertyChangeListener(PropertyChangeListener listener) {\r
+ synchronized (this) {\r
+ listeners = ListenerArray.remove(listeners, listener);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Notify any registered listeners that a bounded property has changed\r
+ * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
+ * @see java.beans.PropertyChangeListener\r
+ * @see java.beans.PropertyChangeEvent\r
+ * @param property the bound property\r
+ * @param oldValue the old value\r
+ * @param newVale the new value\r
+ */\r
+ void firePropertyChange(String property, Object oldValue,\r
+ Object newValue)\r
+ {\r
+ Object[] array = listeners;\r
+ if (array != null) {\r
+ firePropertyChangeImpl(array, property, oldValue, newValue);\r
+ }\r
+ }\r
+\r
+ private void firePropertyChangeImpl(Object[] array, String property,\r
+ Object oldValue, Object newValue)\r
+ {\r
+ for (int i = array.length; i-- != 0;) {\r
+ Object obj = array[i];\r
+ if (obj instanceof PropertyChangeListener) {\r
+ PropertyChangeListener l = (PropertyChangeListener)obj;\r
+ l.propertyChange(new PropertyChangeEvent(\r
+ this, property, oldValue, newValue));\r
+ }\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Report a warning using the error reporter for the current thread.\r
+ *\r
+ * @param message the warning message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportWarning(String message, String sourceName,\r
+ int lineno, String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = Context.getContext();\r
+ cx.getErrorReporter().warning(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ }\r
+\r
+ /**\r
+ * Report a warning using the error reporter for the current thread.\r
+ *\r
+ * @param message the warning message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportWarning(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ Context.reportWarning(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Report an error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportError(String message, String sourceName,\r
+ int lineno, String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = getCurrentContext();\r
+ if (cx != null) {\r
+ cx.errorCount++;\r
+ cx.getErrorReporter().error(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ } else {\r
+ throw new EvaluatorException(message);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Report an error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static void reportError(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ Context.reportError(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Report a runtime error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param lineSource the text of the line (may be null)\r
+ * @param lineOffset the offset into lineSource where problem was detected\r
+ * @return a runtime exception that will be thrown to terminate the\r
+ * execution of the script\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static EvaluatorException reportRuntimeError(String message,\r
+ String sourceName,\r
+ int lineno,\r
+ String lineSource,\r
+ int lineOffset)\r
+ {\r
+ Context cx = getCurrentContext();\r
+ if (cx != null) {\r
+ cx.errorCount++;\r
+ return cx.getErrorReporter().\r
+ runtimeError(message, sourceName, lineno,\r
+ lineSource, lineOffset);\r
+ } else {\r
+ throw new EvaluatorException(message);\r
+ }\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError0(String messageId) {\r
+ return reportRuntimeError(getMessage0(messageId));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError1\r
+ (String messageId, Object arg1) \r
+ {\r
+ return reportRuntimeError(getMessage1(messageId, arg1));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError2\r
+ (String messageId, Object arg1, Object arg2) \r
+ {\r
+ return reportRuntimeError(getMessage2(messageId, arg1, arg2));\r
+ }\r
+\r
+ static EvaluatorException reportRuntimeError3\r
+ (String messageId, Object arg1, Object arg2, Object arg3) \r
+ {\r
+ return reportRuntimeError(getMessage3(messageId, arg1, arg2, arg3));\r
+ }\r
+\r
+ /**\r
+ * Report a runtime error using the error reporter for the current thread.\r
+ *\r
+ * @param message the error message to report\r
+ * @see org.mozilla.javascript.ErrorReporter\r
+ */\r
+ public static EvaluatorException reportRuntimeError(String message) {\r
+ int[] linep = { 0 };\r
+ String filename = getSourcePositionFromStack(linep);\r
+ return Context.reportRuntimeError(message, filename, linep[0], null, 0);\r
+ }\r
+\r
+ /**\r
+ * Initialize the standard objects.\r
+ *\r
+ * Creates instances of the standard objects and their constructors\r
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
+ * as a global object as in ECMA 15.1.<p>\r
+ *\r
+ * This method must be called to initialize a scope before scripts\r
+ * can be evaluated in that scope.\r
+ *\r
+ * @param scope the scope to initialize, or null, in which case a new\r
+ * object will be created to serve as the scope\r
+ * @return the initialized scope\r
+ */\r
+ public Scriptable initStandardObjects(ScriptableObject scope) {\r
+ return initStandardObjects(scope, false);\r
+ }\r
+ \r
+ /**\r
+ * Initialize the standard objects.\r
+ *\r
+ * Creates instances of the standard objects and their constructors\r
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
+ * as a global object as in ECMA 15.1.<p>\r
+ *\r
+ * This method must be called to initialize a scope before scripts\r
+ * can be evaluated in that scope.<p>\r
+ * \r
+ * This form of the method also allows for creating "sealed" standard\r
+ * objects. An object that is sealed cannot have properties added or\r
+ * removed. This is useful to create a "superglobal" that can be shared \r
+ * among several top-level objects. Note that sealing is not allowed in\r
+ * the current ECMA/ISO language specification, but is likely for\r
+ * the next version.\r
+ *\r
+ * @param scope the scope to initialize, or null, in which case a new\r
+ * object will be created to serve as the scope\r
+ * @param sealed whether or not to create sealed standard objects that\r
+ * cannot be modified. \r
+ * @return the initialized scope\r
+ * @since 1.4R3\r
+ */\r
+ public ScriptableObject initStandardObjects(ScriptableObject scope,\r
+ boolean sealed)\r
+ {\r
+ if (scope == null)\r
+ scope = new NativeObject();\r
+\r
+ BaseFunction.init(this, scope, sealed);\r
+ NativeObject.init(this, scope, sealed);\r
+\r
+ Scriptable objectProto = ScriptableObject.getObjectPrototype(scope);\r
+\r
+ // Function.prototype.__proto__ should be Object.prototype\r
+ Scriptable functionProto = ScriptableObject.getFunctionPrototype(scope);\r
+ functionProto.setPrototype(objectProto);\r
+\r
+ // Set the prototype of the object passed in if need be\r
+ if (scope.getPrototype() == null)\r
+ scope.setPrototype(objectProto);\r
+\r
+ // must precede NativeGlobal since it's needed therein\r
+ NativeError.init(this, scope, sealed);\r
+ NativeGlobal.init(this, scope, sealed);\r
+\r
+ NativeArray.init(this, scope, sealed);\r
+ NativeString.init(this, scope, sealed);\r
+ NativeBoolean.init(this, scope, sealed);\r
+ NativeNumber.init(this, scope, sealed);\r
+ NativeDate.init(this, scope, sealed);\r
+ NativeMath.init(this, scope, sealed);\r
+\r
+ NativeWith.init(this, scope, sealed);\r
+ NativeCall.init(this, scope, sealed);\r
+ NativeScript.init(this, scope, sealed);\r
+\r
+ new LazilyLoadedCtor(scope, \r
+ "RegExp",\r
+ "org.mozilla.javascript.regexp.NativeRegExp",\r
+ sealed);\r
+\r
+ // This creates the Packages and java package roots.\r
+ new LazilyLoadedCtor(scope, \r
+ "Packages",\r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ new LazilyLoadedCtor(scope, \r
+ "java", \r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ new LazilyLoadedCtor(scope, \r
+ "getClass",\r
+ "org.mozilla.javascript.NativeJavaPackage",\r
+ sealed);\r
+ \r
+ // Define the JavaAdapter class, allowing it to be overridden.\r
+ String adapterClass = "org.mozilla.javascript.JavaAdapter";\r
+ String adapterProperty = "JavaAdapter";\r
+ try {\r
+ adapterClass = System.getProperty(adapterClass, adapterClass);\r
+ adapterProperty = System.getProperty\r
+ ("org.mozilla.javascript.JavaAdapterClassName",\r
+ adapterProperty);\r
+ }\r
+ catch (SecurityException e) {\r
+ // We may not be allowed to get system properties. Just\r
+ // use the default adapter in that case.\r
+ }\r
+\r
+ new LazilyLoadedCtor(scope, adapterProperty, adapterClass, sealed);\r
+\r
+ return scope;\r
+ }\r
+ \r
+ /**\r
+ * Get the singleton object that represents the JavaScript Undefined value.\r
+ */\r
+ public static Object getUndefinedValue() {\r
+ return Undefined.instance;\r
+ }\r
+ \r
+ /**\r
+ * Evaluate a JavaScript source string.\r
+ *\r
+ * The provided source name and line number are used for error messages\r
+ * and for producing debug information.\r
+ *\r
+ * @param scope the scope to execute in\r
+ * @param source the JavaScript source\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return the result of evaluating the string\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while evaluating the source string\r
+ * @see org.mozilla.javascript.SecuritySupport\r
+ */\r
+ public Object evaluateString(Scriptable scope, String source,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ throws JavaScriptException\r
+ {\r
+ try {\r
+ Reader in = new StringReader(source);\r
+ return evaluateReader(scope, in, sourceName, lineno, \r
+ securityDomain);\r
+ }\r
+ catch (IOException ioe) {\r
+ // Should never occur because we just made the reader from a String\r
+ throw new RuntimeException();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Evaluate a reader as JavaScript source.\r
+ *\r
+ * All characters of the reader are consumed.\r
+ *\r
+ * @param scope the scope to execute in\r
+ * @param in the Reader to get JavaScript source from\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return the result of evaluating the source\r
+ *\r
+ * @exception IOException if an IOException was generated by the Reader\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while evaluating the Reader\r
+ */\r
+ public Object evaluateReader(Scriptable scope, Reader in,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ throws IOException, JavaScriptException\r
+ {\r
+ Script script = compileReader(scope, in, sourceName, lineno, \r
+ securityDomain);\r
+ if (script != null)\r
+ return script.exec(this, scope);\r
+ else\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Check whether a string is ready to be compiled.\r
+ * <p>\r
+ * stringIsCompilableUnit is intended to support interactive compilation of\r
+ * javascript. If compiling the string would result in an error\r
+ * that might be fixed by appending more source, this method\r
+ * returns false. In every other case, it returns true.\r
+ * <p>\r
+ * Interactive shells may accumulate source lines, using this\r
+ * method after each new line is appended to check whether the\r
+ * statement being entered is complete.\r
+ *\r
+ * @param source the source buffer to check\r
+ * @return whether the source is ready for compilation\r
+ * @since 1.4 Release 2\r
+ */\r
+ synchronized public boolean stringIsCompilableUnit(String source)\r
+ {\r
+ Reader in = new StringReader(source);\r
+ // no source name or source text manager, because we're just\r
+ // going to throw away the result.\r
+ TokenStream ts = new TokenStream(in, null, null, 1);\r
+\r
+ // Temporarily set error reporter to always be the exception-throwing\r
+ // DefaultErrorReporter. (This is why the method is synchronized...)\r
+ ErrorReporter currentReporter = \r
+ setErrorReporter(new DefaultErrorReporter());\r
+\r
+ boolean errorseen = false;\r
+ try {\r
+ IRFactory irf = new IRFactory(ts, null);\r
+ Parser p = new Parser(irf);\r
+ p.parse(ts);\r
+ } catch (IOException ioe) {\r
+ errorseen = true;\r
+ } catch (EvaluatorException ee) {\r
+ errorseen = true;\r
+ } finally {\r
+ // Restore the old error reporter.\r
+ setErrorReporter(currentReporter);\r
+ }\r
+ // Return false only if an error occurred as a result of reading past\r
+ // the end of the file, i.e. if the source could be fixed by\r
+ // appending more source.\r
+ if (errorseen && ts.eof())\r
+ return false;\r
+ else \r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Compiles the source in the given reader.\r
+ * <p>\r
+ * Returns a script that may later be executed.\r
+ * Will consume all the source in the reader.\r
+ *\r
+ * @param scope if nonnull, will be the scope in which the script object\r
+ * is created. The script object will be a valid JavaScript object\r
+ * as if it were created using the JavaScript1.3 Script constructor\r
+ * @param in the input reader\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number for reporting errors\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return a script that may later be executed\r
+ * @see org.mozilla.javascript.Script#exec\r
+ * @exception IOException if an IOException was generated by the Reader\r
+ */\r
+ public Script compileReader(Scriptable scope, Reader in, String sourceName,\r
+ int lineno, Object securityDomain)\r
+ throws IOException\r
+ {\r
+ return (Script) compile(scope, in, sourceName, lineno, securityDomain, \r
+ false);\r
+ }\r
+\r
+\r
+ /**\r
+ * Compile a JavaScript function.\r
+ * <p>\r
+ * The function source must be a function definition as defined by\r
+ * ECMA (e.g., "function f(a) { return a; }"). \r
+ *\r
+ * @param scope the scope to compile relative to\r
+ * @param source the function definition source\r
+ * @param sourceName a string describing the source, such as a filename\r
+ * @param lineno the starting line number\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @return a Function that may later be called\r
+ * @see org.mozilla.javascript.Function\r
+ */\r
+ public Function compileFunction(Scriptable scope, String source,\r
+ String sourceName, int lineno,\r
+ Object securityDomain)\r
+ {\r
+ Reader in = new StringReader(source);\r
+ try {\r
+ return (Function) compile(scope, in, sourceName, lineno, \r
+ securityDomain, true);\r
+ }\r
+ catch (IOException ioe) {\r
+ // Should never happen because we just made the reader\r
+ // from a String\r
+ throw new RuntimeException();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Decompile the script.\r
+ * <p>\r
+ * The canonical source of the script is returned.\r
+ *\r
+ * @param script the script to decompile\r
+ * @param scope the scope under which to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the script source\r
+ */\r
+ public String decompileScript(Script script, Scriptable scope,\r
+ int indent)\r
+ {\r
+ NativeScript ns = (NativeScript) script;\r
+ ns.initScript(scope);\r
+ return ns.decompile(this, indent, false);\r
+ }\r
+\r
+ /**\r
+ * Decompile a JavaScript Function.\r
+ * <p>\r
+ * Decompiles a previously compiled JavaScript function object to\r
+ * canonical source.\r
+ * <p>\r
+ * Returns function body of '[native code]' if no decompilation\r
+ * information is available.\r
+ *\r
+ * @param fun the JavaScript function to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the function source\r
+ */\r
+ public String decompileFunction(Function fun, int indent) {\r
+ if (fun instanceof BaseFunction)\r
+ return ((BaseFunction)fun).decompile(this, indent, false);\r
+ else\r
+ return "function " + fun.getClassName() +\r
+ "() {\n\t[native code]\n}\n";\r
+ }\r
+\r
+ /**\r
+ * Decompile the body of a JavaScript Function.\r
+ * <p>\r
+ * Decompiles the body a previously compiled JavaScript Function\r
+ * object to canonical source, omitting the function header and\r
+ * trailing brace.\r
+ *\r
+ * Returns '[native code]' if no decompilation information is available.\r
+ *\r
+ * @param fun the JavaScript function to decompile\r
+ * @param indent the number of spaces to indent the result\r
+ * @return a string representing the function body source.\r
+ */\r
+ public String decompileFunctionBody(Function fun, int indent) {\r
+ if (fun instanceof BaseFunction)\r
+ return ((BaseFunction)fun).decompile(this, indent, true);\r
+ else\r
+ // not sure what the right response here is. JSRef currently\r
+ // dumps core.\r
+ return "[native code]\n";\r
+ }\r
+\r
+ /**\r
+ * Create a new JavaScript object.\r
+ *\r
+ * Equivalent to evaluating "new Object()".\r
+ * @param scope the scope to search for the constructor and to evaluate\r
+ * against\r
+ * @return the new object\r
+ * @exception PropertyException if "Object" cannot be found in\r
+ * the scope\r
+ * @exception NotAFunctionException if the "Object" found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ return newObject(scope, "Object", null);\r
+ }\r
+\r
+ /**\r
+ * Create a new JavaScript object by executing the named constructor.\r
+ *\r
+ * The call <code>newObject(scope, "Foo")</code> is equivalent to\r
+ * evaluating "new Foo()".\r
+ *\r
+ * @param scope the scope to search for the constructor and to evaluate against\r
+ * @param constructorName the name of the constructor to call\r
+ * @return the new object\r
+ * @exception PropertyException if a property with the constructor\r
+ * name cannot be found in the scope\r
+ * @exception NotAFunctionException if the property found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurred while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope, String constructorName)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ return newObject(scope, constructorName, null);\r
+ }\r
+\r
+ /**\r
+ * Creates a new JavaScript object by executing the named constructor.\r
+ *\r
+ * Searches <code>scope</code> for the named constructor, calls it with\r
+ * the given arguments, and returns the result.<p>\r
+ *\r
+ * The code\r
+ * <pre>\r
+ * Object[] args = { "a", "b" };\r
+ * newObject(scope, "Foo", args)</pre>\r
+ * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo\r
+ * constructor has been defined in <code>scope</code>.\r
+ *\r
+ * @param scope The scope to search for the constructor and to evaluate\r
+ * against\r
+ * @param constructorName the name of the constructor to call\r
+ * @param args the array of arguments for the constructor\r
+ * @return the new object\r
+ * @exception PropertyException if a property with the constructor\r
+ * name cannot be found in the scope\r
+ * @exception NotAFunctionException if the property found in the scope\r
+ * is not a function\r
+ * @exception JavaScriptException if an uncaught JavaScript exception\r
+ * occurs while creating the object\r
+ */\r
+ public Scriptable newObject(Scriptable scope, String constructorName,\r
+ Object[] args)\r
+ throws PropertyException,\r
+ NotAFunctionException,\r
+ JavaScriptException\r
+ {\r
+ Object ctorVal = ScriptRuntime.getTopLevelProp(scope, constructorName);\r
+ if (ctorVal == Scriptable.NOT_FOUND) {\r
+ String message = getMessage1("msg.ctor.not.found", constructorName);\r
+ throw new PropertyException(message);\r
+ }\r
+ if (!(ctorVal instanceof Function)) {\r
+ String message = getMessage1("msg.not.ctor", constructorName);\r
+ throw new NotAFunctionException(message);\r
+ }\r
+ Function ctor = (Function) ctorVal;\r
+ return ctor.construct(this, ctor.getParentScope(),\r
+ (args == null) ? ScriptRuntime.emptyArgs : args);\r
+ }\r
+\r
+ /**\r
+ * Create an array with a specified initial length.\r
+ * <p>\r
+ * @param scope the scope to create the object in\r
+ * @param length the initial length (JavaScript arrays may have\r
+ * additional properties added dynamically).\r
+ * @return the new array object\r
+ */\r
+ public Scriptable newArray(Scriptable scope, int length) {\r
+ Scriptable result = new NativeArray(length);\r
+ newArrayHelper(scope, result);\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Create an array with a set of initial elements.\r
+ * <p>\r
+ * @param scope the scope to create the object in\r
+ * @param elements the initial elements. Each object in this array\r
+ * must be an acceptable JavaScript type.\r
+ * @return the new array object\r
+ */\r
+ public Scriptable newArray(Scriptable scope, Object[] elements) {\r
+ Scriptable result = new NativeArray(elements);\r
+ newArrayHelper(scope, result);\r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * Get the elements of a JavaScript array.\r
+ * <p>\r
+ * If the object defines a length property, a Java array with that\r
+ * length is created and initialized with the values obtained by\r
+ * calling get() on object for each value of i in [0,length-1]. If\r
+ * there is not a defined value for a property the Undefined value\r
+ * is used to initialize the corresponding element in the array. The\r
+ * Java array is then returned.\r
+ * If the object doesn't define a length property, null is returned.\r
+ * @param object the JavaScript array or array-like object\r
+ * @return a Java array of objects\r
+ * @since 1.4 release 2\r
+ */\r
+ public Object[] getElements(Scriptable object) {\r
+ double doubleLen = NativeArray.getLengthProperty(object);\r
+ if (doubleLen != doubleLen)\r
+ return null;\r
+ int len = (int) doubleLen;\r
+ Object[] result = new Object[len];\r
+ for (int i=0; i < len; i++) {\r
+ Object elem = object.get(i, object);\r
+ result[i] = elem == Scriptable.NOT_FOUND ? Undefined.instance \r
+ : elem;\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript boolean value.\r
+ * <p>\r
+ * See ECMA 9.2.\r
+ *\r
+ * @param value a JavaScript value\r
+ * @return the corresponding boolean value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static boolean toBoolean(Object value) {\r
+ return ScriptRuntime.toBoolean(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript Number value.\r
+ * <p>\r
+ * Returns a Java double for the JavaScript Number.\r
+ * <p>\r
+ * See ECMA 9.3.\r
+ *\r
+ * @param value a JavaScript value\r
+ * @return the corresponding double value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static double toNumber(Object value) {\r
+ return ScriptRuntime.toNumber(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to a JavaScript String value.\r
+ * <p>\r
+ * See ECMA 9.8.\r
+ * <p>\r
+ * @param value a JavaScript value\r
+ * @return the corresponding String value converted using\r
+ * the ECMA rules\r
+ */\r
+ public static String toString(Object value) {\r
+ return ScriptRuntime.toString(value);\r
+ }\r
+\r
+ /**\r
+ * Convert the value to an JavaScript object value.\r
+ * <p>\r
+ * Note that a scope must be provided to look up the constructors\r
+ * for Number, Boolean, and String.\r
+ * <p>\r
+ * See ECMA 9.9.\r
+ * <p>\r
+ * Additionally, arbitrary Java objects and classes will be\r
+ * wrapped in a Scriptable object with its Java fields and methods\r
+ * reflected as JavaScript properties of the object.\r
+ *\r
+ * @param value any Java object\r
+ * @param scope global scope containing constructors for Number,\r
+ * Boolean, and String\r
+ * @return new JavaScript object\r
+ */\r
+ public static Scriptable toObject(Object value, Scriptable scope) {\r
+ return ScriptRuntime.toObject(scope, value, null);\r
+ }\r
+ \r
+ /**\r
+ * Convert the value to an JavaScript object value.\r
+ * <p>\r
+ * Note that a scope must be provided to look up the constructors\r
+ * for Number, Boolean, and String.\r
+ * <p>\r
+ * See ECMA 9.9.\r
+ * <p>\r
+ * Additionally, arbitrary Java objects and classes will be\r
+ * wrapped in a Scriptable object with its Java fields and methods\r
+ * reflected as JavaScript properties of the object. If the \r
+ * "staticType" parameter is provided, it will be used as the static\r
+ * type of the Java value to create.\r
+ *\r
+ * @param value any Java object\r
+ * @param scope global scope containing constructors for Number,\r
+ * Boolean, and String\r
+ * @param staticType the static type of the Java value to create\r
+ * @return new JavaScript object\r
+ */\r
+ public static Scriptable toObject(Object value, Scriptable scope, \r
+ Class staticType) {\r
+ if (value == null && staticType != null)\r
+ return null;\r
+ return ScriptRuntime.toObject(scope, value, staticType);\r
+ }\r
+\r
+ /**\r
+ * Tell whether debug information is being generated.\r
+ * @since 1.3\r
+ */\r
+ public boolean isGeneratingDebug() {\r
+ return generatingDebug;\r
+ }\r
+\r
+ /**\r
+ * Specify whether or not debug information should be generated.\r
+ * <p>\r
+ * Setting the generation of debug information on will set the\r
+ * optimization level to zero.\r
+ * @since 1.3\r
+ */\r
+ public void setGeneratingDebug(boolean generatingDebug) {\r
+ generatingDebugChanged = true;\r
+ if (generatingDebug)\r
+ setOptimizationLevel(0);\r
+ this.generatingDebug = generatingDebug;\r
+ }\r
+\r
+ /**\r
+ * Tell whether source information is being generated.\r
+ * @since 1.3\r
+ */\r
+ public boolean isGeneratingSource() {\r
+ return generatingSource;\r
+ }\r
+\r
+ /**\r
+ * Specify whether or not source information should be generated.\r
+ * <p>\r
+ * Without source information, evaluating the "toString" method\r
+ * on JavaScript functions produces only "[native code]" for\r
+ * the body of the function.\r
+ * Note that code generated without source is not fully ECMA\r
+ * conformant.\r
+ * @since 1.3\r
+ */\r
+ public void setGeneratingSource(boolean generatingSource) {\r
+ this.generatingSource = generatingSource;\r
+ }\r
+\r
+ /**\r
+ * Get the current optimization level.\r
+ * <p>\r
+ * The optimization level is expressed as an integer between -1 and\r
+ * 9.\r
+ * @since 1.3\r
+ *\r
+ */\r
+ public int getOptimizationLevel() {\r
+ return optimizationLevel;\r
+ }\r
+\r
+ /**\r
+ * Set the current optimization level.\r
+ * <p>\r
+ * The optimization level is expected to be an integer between -1 and\r
+ * 9. Any negative values will be interpreted as -1, and any values\r
+ * greater than 9 will be interpreted as 9.\r
+ * An optimization level of -1 indicates that interpretive mode will\r
+ * always be used. Levels 0 through 9 indicate that class files may \r
+ * be generated. Higher optimization levels trade off compile time\r
+ * performance for runtime performance.\r
+ * The optimizer level can't be set greater than -1 if the optimizer\r
+ * package doesn't exist at run time.\r
+ * @param optimizationLevel an integer indicating the level of\r
+ * optimization to perform\r
+ * @since 1.3\r
+ *\r
+ */\r
+ public void setOptimizationLevel(int optimizationLevel) {\r
+ if (optimizationLevel < 0) {\r
+ optimizationLevel = -1;\r
+ } else if (optimizationLevel > 9) {\r
+ optimizationLevel = 9;\r
+ }\r
+ if (codegenClass == null)\r
+ optimizationLevel = -1;\r
+ this.optimizationLevel = optimizationLevel;\r
+ }\r
+\r
+ /**\r
+ * Get the current target class file name.\r
+ * <p>\r
+ * If nonnull, requests to compile source will result in one or\r
+ * more class files being generated.\r
+ * @since 1.3\r
+ */\r
+ public String getTargetClassFileName() {\r
+ return nameHelper == null\r
+ ? null \r
+ : nameHelper.getTargetClassFileName();\r
+ }\r
+\r
+ /**\r
+ * Set the current target class file name.\r
+ * <p>\r
+ * If nonnull, requests to compile source will result in one or\r
+ * more class files being generated. If null, classes will only\r
+ * be generated in memory.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public void setTargetClassFileName(String classFileName) {\r
+ if (nameHelper != null)\r
+ nameHelper.setTargetClassFileName(classFileName);\r
+ }\r
+\r
+ /**\r
+ * Get the current package to generate classes into.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public String getTargetPackage() {\r
+ return (nameHelper == null) ? null : nameHelper.getTargetPackage();\r
+ }\r
+\r
+ /**\r
+ * Set the package to generate classes into.\r
+ *\r
+ * @since 1.3\r
+ */\r
+ public void setTargetPackage(String targetPackage) {\r
+ if (nameHelper != null)\r
+ nameHelper.setTargetPackage(targetPackage);\r
+ }\r
+\r
+ /**\r
+ * Get the current interface to write class bytes into.\r
+ *\r
+ * @see ClassOutput\r
+ * @since 1.5 Release 2\r
+ */\r
+ public ClassOutput getClassOutput() {\r
+ return nameHelper == null ? null : nameHelper.getClassOutput();\r
+ }\r
+\r
+ /**\r
+ * Set the interface to write class bytes into.\r
+ * Unless setTargetClassFileName() has been called classOutput will be\r
+ * used each time the javascript compiler has generated the bytecode for a\r
+ * script class.\r
+ *\r
+ * @see ClassOutput\r
+ * @since 1.5 Release 2\r
+ */\r
+ public void setClassOutput(ClassOutput classOutput) {\r
+ if (nameHelper != null)\r
+ nameHelper.setClassOutput(classOutput);\r
+ }\r
+ \r
+ /**\r
+ * Add a Context listener.\r
+ */\r
+ public static void addContextListener(ContextListener listener) {\r
+ synchronized (staticDataLock) {\r
+ contextListeners = ListenerArray.add(contextListeners, listener);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Remove a Context listener.\r
+ * @param listener the listener to remove.\r
+ */\r
+ public static void removeContextListener(ContextListener listener) {\r
+ synchronized (staticDataLock) {\r
+ contextListeners = ListenerArray.remove(contextListeners, listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the security support for this context. \r
+ * <p> SecuritySupport may only be set if it is currently null.\r
+ * Otherwise a SecurityException is thrown.\r
+ * @param supportObj a SecuritySupport object\r
+ * @throws SecurityException if there is already a SecuritySupport\r
+ * object for this Context\r
+ */\r
+ public synchronized void setSecuritySupport(SecuritySupport supportObj) {\r
+ if (securitySupport != null) {\r
+ throw new SecurityException("Cannot overwrite existing " +\r
+ "SecuritySupport object");\r
+ }\r
+ securitySupport = supportObj;\r
+ }\r
+ \r
+ /**\r
+ * Return true if a security domain is required on calls to\r
+ * compile and evaluate scripts.\r
+ *\r
+ * @since 1.4 Release 2\r
+ */\r
+ public static boolean isSecurityDomainRequired() { \r
+ return requireSecurityDomain;\r
+ }\r
+ \r
+ /**\r
+ * Returns the security context associated with the innermost\r
+ * script or function being executed by the interpreter.\r
+ * @since 1.4 release 2\r
+ */\r
+ public Object getInterpreterSecurityDomain() {\r
+ return interpreterSecurityDomain;\r
+ }\r
+ \r
+ /**\r
+ * Returns true if the class parameter is a class in the \r
+ * interpreter. Typically used by embeddings that get a class\r
+ * context to check security. These embeddings must know \r
+ * whether to get the security context associated with the\r
+ * interpreter or not.\r
+ * \r
+ * @param cl a class to test whether or not it is an interpreter\r
+ * class\r
+ * @return true if cl is an interpreter class\r
+ * @since 1.4 release 2\r
+ */\r
+ public boolean isInterpreterClass(Class cl) {\r
+ return cl == Interpreter.class;\r
+ }\r
+ \r
+ /**\r
+ * Set the class that the generated target will extend.\r
+ * \r
+ * @param extendsClass the class it extends\r
+ */\r
+ public void setTargetExtends(Class extendsClass) {\r
+ if (nameHelper != null) {\r
+ nameHelper.setTargetExtends(extendsClass);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Set the interfaces that the generated target will implement.\r
+ * \r
+ * @param implementsClasses an array of Class objects, one for each\r
+ * interface the target will extend\r
+ */\r
+ public void setTargetImplements(Class[] implementsClasses) {\r
+ if (nameHelper != null) {\r
+ nameHelper.setTargetImplements(implementsClasses);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Get a value corresponding to a key.\r
+ * <p>\r
+ * Since the Context is associated with a thread it can be \r
+ * used to maintain values that can be later retrieved using \r
+ * the current thread. \r
+ * <p>\r
+ * Note that the values are maintained with the Context, so\r
+ * if the Context is disassociated from the thread the values\r
+ * cannot be retreived. Also, if private data is to be maintained\r
+ * in this manner the key should be a java.lang.Object \r
+ * whose reference is not divulged to untrusted code.\r
+ * @param key the key used to lookup the value\r
+ * @return a value previously stored using putThreadLocal.\r
+ */\r
+ public Object getThreadLocal(Object key) {\r
+ if (hashtable == null)\r
+ return null;\r
+ return hashtable.get(key);\r
+ }\r
+\r
+ /**\r
+ * Put a value that can later be retrieved using a given key.\r
+ * <p>\r
+ * @param key the key used to index the value\r
+ * @param value the value to save\r
+ */\r
+ public void putThreadLocal(Object key, Object value) {\r
+ if (hashtable == null)\r
+ hashtable = new Hashtable();\r
+ hashtable.put(key, value);\r
+ }\r
+ \r
+ /**\r
+ * Remove values from thread-local storage.\r
+ * @param key the key for the entry to remove.\r
+ * @since 1.5 release 2\r
+ */\r
+ public void removeThreadLocal(Object key) {\r
+ if (hashtable == null)\r
+ return;\r
+ hashtable.remove(key);\r
+ } \r
+ \r
+ /**\r
+ * Return whether functions are compiled by this context using\r
+ * dynamic scope.\r
+ * <p>\r
+ * If functions are compiled with dynamic scope, then they execute\r
+ * in the scope of their caller, rather than in their parent scope.\r
+ * This is useful for sharing functions across multiple scopes.\r
+ * @since 1.5 Release 1\r
+ */\r
+ public boolean hasCompileFunctionsWithDynamicScope() {\r
+ return compileFunctionsWithDynamicScopeFlag;\r
+ }\r
+ \r
+ /**\r
+ * Set whether functions compiled by this context should use\r
+ * dynamic scope.\r
+ * <p>\r
+ * @param flag if true, compile functions with dynamic scope\r
+ * @since 1.5 Release 1\r
+ */\r
+ public void setCompileFunctionsWithDynamicScope(boolean flag) {\r
+ compileFunctionsWithDynamicScopeFlag = flag;\r
+ }\r
+ \r
+ /**\r
+ * Set whether to cache some values statically.\r
+ * <p>\r
+ * By default, the engine will cache some values statically \r
+ * (reflected Java classes, for instance). This can speed\r
+ * execution dramatically, but increases the memory footprint.\r
+ * Also, with caching enabled, references may be held to \r
+ * objects past the lifetime of any real usage. \r
+ * <p>\r
+ * If caching is enabled and this method is called with a \r
+ * <code>false</code> argument, the caches will be emptied.\r
+ * So one strategy could be to clear the caches at times\r
+ * appropriate to the application.\r
+ * <p>\r
+ * Caching is enabled by default.\r
+ * \r
+ * @param cachingEnabled if true, caching is enabled\r
+ * @since 1.5 Release 1 \r
+ */\r
+ public static void setCachingEnabled(boolean cachingEnabled) {\r
+ if (isCachingEnabled && !cachingEnabled) {\r
+ // Caching is being turned off. Empty caches.\r
+ JavaMembers.classTable = new Hashtable();\r
+ nameHelper.reset();\r
+ }\r
+ isCachingEnabled = cachingEnabled;\r
+ FunctionObject.setCachingEnabled(cachingEnabled);\r
+ }\r
+ \r
+ /**\r
+ * Set a WrapHandler for this Context.\r
+ * <p>\r
+ * The WrapHandler allows custom object wrapping behavior for \r
+ * Java object manipulated with JavaScript.\r
+ * @see org.mozilla.javascript.WrapHandler\r
+ * @since 1.5 Release 2 \r
+ */\r
+ public void setWrapHandler(WrapHandler wrapHandler) {\r
+ this.wrapHandler = wrapHandler;\r
+ }\r
+ \r
+ /**\r
+ * Return the current WrapHandler, or null if none is defined.\r
+ * @see org.mozilla.javascript.WrapHandler\r
+ * @since 1.5 Release 2 \r
+ */\r
+ public WrapHandler getWrapHandler() {\r
+ return wrapHandler;\r
+ }\r
+ \r
+ public DebuggableEngine getDebuggableEngine() {\r
+ if (debuggableEngine == null)\r
+ debuggableEngine = new DebuggableEngineImpl(this);\r
+ return debuggableEngine;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * if hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,\r
+ * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000\r
+ * in deviation with Ecma B.2.4\r
+ */\r
+ public static final int FEATURE_NON_ECMA_GET_YEAR = 1;\r
+ \r
+ /**\r
+ * Controls certain aspects of script semantics. \r
+ * Should be overwritten to alter default behavior.\r
+ * @param featureIndex feature index to check\r
+ * @return true if the <code>featureIndex</code> feature is turned on\r
+ * @see #FEATURE_NON_ECMA_GET_YEAR\r
+ */\r
+ public boolean hasFeature(int featureIndex) {\r
+ if (featureIndex == FEATURE_NON_ECMA_GET_YEAR) {\r
+ /*\r
+ * During the great date rewrite of 1.3, we tried to track the\r
+ * evolving ECMA standard, which then had a definition of\r
+ * getYear which always subtracted 1900. Which we\r
+ * implemented, not realizing that it was incompatible with\r
+ * the old behavior... now, rather than thrash the behavior\r
+ * yet again, we've decided to leave it with the - 1900\r
+ * behavior and point people to the getFullYear method. But\r
+ * we try to protect existing scripts that have specified a\r
+ * version...\r
+ */\r
+ return (version == Context.VERSION_1_0 \r
+ || version == Context.VERSION_1_1\r
+ || version == Context.VERSION_1_2);\r
+ }\r
+ throw new RuntimeException("Bad feature index: " + featureIndex);\r
+ }\r
+\r
+ /**\r
+ * Get/Set threshold of executed instructions counter that triggers call to\r
+ * <code>observeInstructionCount()</code>.\r
+ * When the threshold is zero, instruction counting is disabled, \r
+ * otherwise each time the run-time executes at least the threshold value\r
+ * of script instructions, <code>observeInstructionCount()</code> will \r
+ * be called.\r
+ */\r
+ public int getInstructionObserverThreshold() {\r
+ return instructionThreshold;\r
+ }\r
+ \r
+ public void setInstructionObserverThreshold(int threshold) {\r
+ instructionThreshold = threshold;\r
+ }\r
+ \r
+ /** \r
+ * Allow application to monitor counter of executed script instructions\r
+ * in Context subclasses.\r
+ * Run-time calls this when instruction counting is enabled and the counter\r
+ * reaches limit set by <code>setInstructionObserverThreshold()</code>.\r
+ * The method is useful to observe long running scripts and if necessary\r
+ * to terminate them.\r
+ * @param instructionCount amount of script instruction executed since \r
+ * last call to <code>observeInstructionCount</code> \r
+ * @throws Error to terminate the script\r
+ */\r
+ protected void observeInstructionCount(int instructionCount) {}\r
+ \r
+ /********** end of API **********/\r
+ \r
+ void pushFrame(DebugFrame frame) {\r
+ if (frameStack == null)\r
+ frameStack = new java.util.Stack();\r
+ frameStack.push(frame);\r
+ }\r
+ \r
+ void popFrame() {\r
+ frameStack.pop();\r
+ }\r
+ \r
+\r
+\r
+ static String getMessage0(String messageId) {\r
+ return getMessage(messageId, null);\r
+ }\r
+\r
+ static String getMessage1(String messageId, Object arg1) {\r
+ Object[] arguments = {arg1};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+\r
+ static String getMessage2(String messageId, Object arg1, Object arg2) {\r
+ Object[] arguments = {arg1, arg2};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+\r
+ static String getMessage3\r
+ (String messageId, Object arg1, Object arg2, Object arg3) {\r
+ Object[] arguments = {arg1, arg2, arg3};\r
+ return getMessage(messageId, arguments);\r
+ }\r
+ /**\r
+ * Internal method that reports an error for missing calls to\r
+ * enter().\r
+ */\r
+ static Context getContext() {\r
+ Thread t = Thread.currentThread();\r
+ Context cx = (Context) threadContexts.get(t);\r
+ if (cx == null) {\r
+ throw new RuntimeException(\r
+ "No Context associated with current Thread");\r
+ }\r
+ return cx;\r
+ }\r
+\r
+ /** GCJ doesn't have an easy way to bundle up .properties files, so we do this */\r
+ static class HardCodedResourceBundle extends ListResourceBundle {\r
+ public Object[][] getContents() { return contents; }\r
+ static final Object[][] contents = {\r
+ { "msg.dup.parms", "Duplicate parameter name \"{0}\"." },\r
+ { "msg.ctor.not.found", "Constructor for \"{0}\" not found." },\r
+ { "msg.not.ctor", "\"{0}\" is not a constructor." },\r
+ { "msg.varargs.ctor", "Method or constructor \"{0}\" must be static with the signature \"(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)\" to define a variable arguments constructor." },\r
+ { "msg.varargs.fun", "Method \"{0}\" must be static with the signature \"(Context cx, Scriptable thisObj, Object[] args, Function funObj)\" to define a variable arguments function." },\r
+ { "msg.incompat.call", "Method \"{0}\" called on incompatible object." },\r
+ { "msg.bad.parms", "Bad method parameters for \"{0}\"." },\r
+ { "msg.no.overload", "Method \"{0}\" occurs multiple times in class \"{1}\"." },\r
+ { "msg.method.not.found", "Method \"{0}\" not found in \"{1}\"." },\r
+ { "msg.bad.for.in.lhs", "Invalid left-hand side of for..in loop." },\r
+ { "msg.bad.lhs.assign", "Invalid assignment left-hand side." },\r
+ { "msg.mult.index", "Only one variable allowed in for..in loop." },\r
+ { "msg.cant.convert", "Can''t convert to type \"{0}\"." },\r
+ { "msg.cant.call.indirect", "Function \"{0}\" must be called directly, and not by way of a function of another name." },\r
+ { "msg.eval.nonstring", "Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended?" },\r
+ { "msg.only.from.new", "\"{0}\" may only be invoked from a \"new\" expression." },\r
+ { "msg.deprec.ctor", "The \"{0}\" constructor is deprecated." },\r
+ { "msg.no.function.ref.found.in", "no source found in {1} to decompile function reference {0}" },\r
+ { "msg.no.function.ref.found", "no source found to decompile function reference {0}" },\r
+ { "msg.arg.isnt.array", "second argument to Function.prototype.apply must be an array" },\r
+ { "msg.bad.esc.mask", "invalid string escape mask" },\r
+ { "msg.cant.instantiate", "error instantiating ({0}): class {1} is interface or abstract" },\r
+ { "msg.bad.ctor.sig", "Found constructor with wrong signature: {0} calling {1} with signature {2}" },\r
+ { "msg.not.java.obj", "Expected argument to getClass() to be a Java object." },\r
+ { "msg.no.java.ctor", "Java constructor for \"{0}\" with arguments \"{1}\" not found." },\r
+ { "msg.method.ambiguous", "The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3}" },\r
+ { "msg.constructor.ambiguous", "The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2}" },\r
+ { "msg.conversion.not.allowed", "Cannot convert {0} to {1}" },\r
+ { "msg.bad.quant", "Invalid quantifier {0}" },\r
+ { "msg.overlarge.max", "Overly large maximum {0}" },\r
+ { "msg.zero.quant", "Zero quantifier {0}" },\r
+ { "msg.max.lt.min", "Maximum {0} less than minimum" },\r
+ { "msg.unterm.quant", "Unterminated quantifier {0}" },\r
+ { "msg.unterm.paren", "Unterminated parenthetical {0}" },\r
+ { "msg.unterm.class", "Unterminated character class {0}" },\r
+ { "msg.bad.range", "Invalid range in character class." },\r
+ { "msg.trail.backslash", "Trailing \\ in regular expression." },\r
+ { "msg.no.regexp", "Regular expressions are not available." },\r
+ { "msg.bad.backref", "back-reference exceeds number of capturing parentheses." },\r
+ { "msg.dup.label", "Duplicate label {0}." },\r
+ { "msg.undef.label", "Undefined label {0}." },\r
+ { "msg.bad.break", "Unlabelled break must be inside loop or switch." },\r
+ { "msg.continue.outside", "continue must be inside loop." },\r
+ { "msg.continue.nonloop", "Can only continue to labeled iteration statement." },\r
+ { "msg.fn.redecl", "Function \"{0}\" redeclared; prior definition will be ignored." },\r
+ { "msg.no.paren.parms", "missing ( before function parameters" },\r
+ { "msg.no.parm", "missing formal parameter" },\r
+ { "msg.no.paren.after.parms", "missing ) after formal parameters" },\r
+ { "msg.no.brace.body", "missing '{' before function body" },\r
+ { "msg.no.brace.after.body", "missing } after function body" },\r
+ { "msg.no.paren.cond", "missing ( before condition" },\r
+ { "msg.no.paren.after.cond", "missing ) after condition" },\r
+ { "msg.no.semi.stmt", "missing ; before statement" },\r
+ { "msg.no.name.after.dot", "missing name after . operator" },\r
+ { "msg.no.bracket.index", "missing ] in index expression" },\r
+ { "msg.no.paren.switch", "missing ( before switch expression" },\r
+ { "msg.no.paren.after.switch", "missing ) after switch expression" },\r
+ { "msg.no.brace.switch", "missing '{' before switch body" },\r
+ { "msg.bad.switch", "invalid switch statement" },\r
+ { "msg.no.colon.case", "missing : after case expression" },\r
+ { "msg.no.while.do", "missing while after do-loop body" },\r
+ { "msg.no.paren.for", "missing ( after for" },\r
+ { "msg.no.semi.for", "missing ; after for-loop initializer" },\r
+ { "msg.no.semi.for.cond", "missing ; after for-loop condition" },\r
+ { "msg.no.paren.for.ctrl", "missing ) after for-loop control" },\r
+ { "msg.no.paren.with", "missing ( before with-statement object" },\r
+ { "msg.no.paren.after.with", "missing ) after with-statement object" },\r
+ { "msg.bad.return", "invalid return" },\r
+ { "msg.no.brace.block", "missing } in compound statement" },\r
+ { "msg.bad.label", "invalid label" },\r
+ { "msg.bad.var", "missing variable name" },\r
+ { "msg.bad.var.init", "invalid variable initialization" },\r
+ { "msg.no.colon.cond", "missing : in conditional expression" },\r
+ { "msg.no.paren.arg", "missing ) after argument list" },\r
+ { "msg.no.bracket.arg", "missing ] after element list" },\r
+ { "msg.bad.prop", "invalid property id" },\r
+ { "msg.no.colon.prop", "missing : after property id" },\r
+ { "msg.no.brace.prop", "missing } after property list" },\r
+ { "msg.no.paren", "missing ) in parenthetical" },\r
+ { "msg.reserved.id", "identifier is a reserved word" },\r
+ { "msg.no.paren.catch", "missing ( before catch-block condition" },\r
+ { "msg.bad.catchcond", "invalid catch block condition" },\r
+ { "msg.catch.unreachable", "any catch clauses following an unqualified catch are unreachable" },\r
+ { "msg.no.brace.catchblock", "missing '{' before catch-block body" },\r
+ { "msg.try.no.catchfinally", "''try'' without ''catch'' or ''finally''" },\r
+ { "msg.syntax", "syntax error" },\r
+ { "msg.assn.create", "Assignment to undefined \"{0}\" will create a new variable. Add a variable statement at the top level scope to remove this warning." },\r
+ { "msg.prop.not.found", "Property not found." },\r
+ { "msg.invalid.type", "Invalid JavaScript value of type {0}" },\r
+ { "msg.primitive.expected", "Primitive type expected (had {0} instead)" },\r
+ { "msg.null.to.object", "Cannot convert null to an object." },\r
+ { "msg.undef.to.object", "Cannot convert undefined to an object." },\r
+ { "msg.cyclic.value", "Cyclic {0} value not allowed." },\r
+ { "msg.is.not.defined", "\"{0}\" is not defined." },\r
+ { "msg.isnt.function", "{0} is not a function." },\r
+ { "msg.bad.default.value", "Object''s getDefaultValue() method returned an object." },\r
+ { "msg.instanceof.not.object", " Can''t use instanceof on a non-object." },\r
+ { "msg.instanceof.bad.prototype", " ''prototype'' property of {0} is not an object." },\r
+ { "msg.bad.radix", " illegal radix {0}." },\r
+ { "msg.default.value", "Cannot find default value for object." },\r
+ { "msg.zero.arg.ctor", "Cannot load class \"{0}\" which has no zero-parameter constructor." },\r
+ { "msg.multiple.ctors", "Cannot have more than one constructor method, but found both {0} and {1}." },\r
+ { "msg.ctor.multiple.parms", "Can''t define constructor or class {0} since more than one constructor has multiple parameters." },\r
+ { "msg.extend.scriptable", "{0} must extend ScriptableObject in order to define property {1}." },\r
+ { "msg.bad.getter.parms", "In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter." },\r
+ { "msg.obj.getter.parms", "Expected static or delegated getter {0} to take a ScriptableObject parameter." },\r
+ { "msg.getter.static", "Getter and setter must both be static or neither be static." },\r
+ { "msg.setter2.parms", "Two-parameter setter must take a ScriptableObject as its first parameter." },\r
+ { "msg.setter1.parms", "Expected single parameter setter for {0}" },\r
+ { "msg.setter2.expected", "Expected static or delegated setter {0} to take two parameters." },\r
+ { "msg.setter.parms", "Expected either one or two parameters for setter." },\r
+ { "msg.add.sealed", "Cannot add a property to a sealed object." },\r
+ { "msg.remove.sealed", "Cannot remove a property from a sealed object." },\r
+ { "msg.token.replaces.pushback", "ungot token {0} replaces pushback token {1}" },\r
+ { "msg.missing.exponent", "missing exponent" },\r
+ { "msg.caught.nfe", "number format error: {0}" },\r
+ { "msg.unterminated.string.lit", "unterminated string literal" },\r
+ { "msg.oct.esc.too.large", "octal escape too large" },\r
+ { "msg.nested.comment", "nested comment" },\r
+ { "msg.unterminated.comment", "unterminated comment" },\r
+ { "msg.unterminated.re.lit", "unterminated regular expression literal" },\r
+ { "msg.invalid.re.flag", "invalid flag after regular expression" },\r
+ { "msg.no.re.input.for", "no input for {0}" },\r
+ { "msg.illegal.character", "illegal character" },\r
+ { "msg.invalid.escape", "invalid Unicode escape sequence" },\r
+ { "msg.bad.octal.literal", "illegal octal literal digit {0}; interpreting it as a decimal digit" },\r
+ { "msg.undefined", "The undefined value has no properties." },\r
+ { "msg.java.internal.field.type", "Internal error: type conversion of {0} to assign to {1} on {2} failed." },\r
+ { "msg.java.conversion.implicit_method", "Can''t find converter method \"{0}\" on class {1}." },\r
+ { "msg.java.method.assign", "Java method \"{0}\" cannot be assigned to." },\r
+ { "msg.java.internal.private", "Internal error: attempt to access private/protected field \"{0}\"." },\r
+ { "msg.java.no_such_method", "Can''t find method {0}." },\r
+ { "msg.script.is.not.constructor", "Script objects are not constructors." },\r
+ { "msg.nonjava.method", "Java method \"{0}\" was invoked with a ''this'' value that was not a Java object." },\r
+ { "msg.java.member.not.found", "Java class \"{0}\" has no public instance field or method named \"{1}\"." },\r
+ { "msg.pkg.int", "Java package names may not be numbers." },\r
+ { "msg.ambig.import", "Ambiguous import: \"{0}\" and and \"{1}\"." },\r
+ { "msg.not.pkg", "Function importPackage must be called with a package; had \"{0}\" instead." },\r
+ { "msg.not.class", "Function importClass must be called with a class; had \"{0}\" instead." },\r
+ { "msg.prop.defined", "Cannot import \"{0}\" since a property by that name is already defined." },\r
+ { "msg.arraylength.bad", "Inappropriate array length." },\r
+ { "msg.bad.uri", "Malformed URI sequence." },\r
+ { "msg.bad.precision", "Precision {0} out of range." }\r
+ };\r
+ }\r
+\r
+ static final ResourceBundle myresources = new HardCodedResourceBundle();\r
+\r
+ /* OPT there's a noticable delay for the first error! Maybe it'd\r
+ * make sense to use a ListResourceBundle instead of a properties\r
+ * file to avoid (synchronized) text parsing.\r
+ */\r
+ static String getMessage(String messageId, Object[] arguments) {\r
+ Context cx = getCurrentContext();\r
+ Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();\r
+\r
+ // ResourceBundle does cacheing.\r
+ ResourceBundle rb = myresources;\r
+\r
+ String formatString;\r
+ try {\r
+ formatString = rb.getString(messageId);\r
+ } catch (java.util.MissingResourceException mre) {\r
+ throw new RuntimeException\r
+ ("no message resource found for message property "+ messageId);\r
+ }\r
+\r
+ /*\r
+ * It's OK to format the string, even if 'arguments' is null;\r
+ * we need to format it anyway, to make double ''s collapse to\r
+ * single 's.\r
+ */\r
+ // TODO: MessageFormat is not available on pJava\r
+ MessageFormat formatter = new MessageFormat(formatString);\r
+ return formatter.format(arguments);\r
+ }\r
+\r
+ // debug flags\r
+ static final boolean printTrees = false;\r
+ \r
+ /**\r
+ * Compile a script.\r
+ *\r
+ * Reads script source from the reader and compiles it, returning\r
+ * a class for either the script or the function depending on the\r
+ * value of <code>returnFunction</code>.\r
+ *\r
+ * @param scope the scope to compile relative to\r
+ * @param in the Reader to read source from\r
+ * @param sourceName the name of the origin of the source (usually\r
+ * a file or URL)\r
+ * @param lineno the line number of the start of the source\r
+ * @param securityDomain an arbitrary object that specifies security \r
+ * information about the origin or owner of the script. For \r
+ * implementations that don't care about security, this value \r
+ * may be null.\r
+ * @param returnFunction if true, will expect the source to contain\r
+ * a function; return value is assumed to\r
+ * then be a org.mozilla.javascript.Function\r
+ * @return a class for the script or function\r
+ * @see org.mozilla.javascript.Context#compileReader\r
+ */\r
+ private Object compile(Scriptable scope, Reader in, String sourceName, \r
+ int lineno, Object securityDomain, \r
+ boolean returnFunction)\r
+ throws IOException\r
+ {\r
+ if (debugger != null && in != null) {\r
+ in = new DebugReader(in);\r
+ }\r
+ TokenStream ts = new TokenStream(in, scope, sourceName, lineno);\r
+ return compile(scope, ts, securityDomain, in, returnFunction);\r
+ }\r
+\r
+ private static Class codegenClass = null;\r
+ private static ClassNameHelper nameHelper = null;\r
+ static {\r
+ /*\r
+ try {\r
+ codegenClass = Class.forName(\r
+ "org.mozilla.javascript.optimizer.Codegen");\r
+ Class nameHelperClass = Class.forName(\r
+ "org.mozilla.javascript.optimizer.OptClassNameHelper");\r
+ nameHelper = (ClassNameHelper)nameHelperClass.newInstance();\r
+ } catch (ClassNotFoundException x) {\r
+ // ...must be running lite, that's ok\r
+ codegenClass = null;\r
+ } catch (IllegalAccessException x) {\r
+ codegenClass = null;\r
+ } catch (InstantiationException x) {\r
+ codegenClass = null;\r
+ }\r
+ */\r
+ }\r
+ \r
+ private Interpreter getCompiler() {\r
+ if (codegenClass != null) {\r
+ try {\r
+ return (Interpreter) codegenClass.newInstance();\r
+ }\r
+ catch (SecurityException x) { \r
+ }\r
+ catch (IllegalArgumentException x) {\r
+ }\r
+ catch (InstantiationException x) {\r
+ }\r
+ catch (IllegalAccessException x) {\r
+ }\r
+ // fall through\r
+ }\r
+ return new Interpreter();\r
+ }\r
+ \r
+ private Object compile(Scriptable scope, TokenStream ts, \r
+ Object securityDomain, Reader in,\r
+ boolean returnFunction)\r
+ throws IOException\r
+ {\r
+ Interpreter compiler = optimizationLevel == -1 \r
+ ? new Interpreter()\r
+ : getCompiler();\r
+ \r
+ errorCount = 0;\r
+ IRFactory irf = compiler.createIRFactory(ts, nameHelper, scope);\r
+ Parser p = new Parser(irf);\r
+ Node tree = (Node) p.parse(ts);\r
+ if (tree == null) \r
+ return null;\r
+\r
+ tree = compiler.transform(tree, ts, scope);\r
+\r
+ if (printTrees)\r
+ System.out.println(tree.toStringTree());\r
+ \r
+ if (returnFunction) {\r
+ Node first = tree.getFirstChild();\r
+ if (first == null)\r
+ return null;\r
+ tree = (Node) first.getProp(Node.FUNCTION_PROP);\r
+ if (tree == null)\r
+ return null;\r
+ }\r
+ \r
+ if (in instanceof DebugReader) {\r
+ DebugReader dr = (DebugReader) in;\r
+ tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());\r
+ }\r
+\r
+ Object result = compiler.compile(this, scope, tree, securityDomain,\r
+ securitySupport, nameHelper);\r
+\r
+ return errorCount == 0 ? result : null;\r
+ }\r
+\r
+ static String getSourcePositionFromStack(int[] linep) {\r
+ Context cx = getCurrentContext();\r
+ if (cx == null)\r
+ return null;\r
+ if (cx.interpreterLine > 0 && cx.interpreterSourceFile != null) {\r
+ linep[0] = cx.interpreterLine;\r
+ return cx.interpreterSourceFile;\r
+ }\r
+ /**\r
+ * A bit of a hack, but the only way to get filename and line\r
+ * number from an enclosing frame.\r
+ */\r
+ CharArrayWriter writer = new CharArrayWriter();\r
+ RuntimeException re = new RuntimeException();\r
+ re.printStackTrace(new PrintWriter(writer));\r
+ String s = writer.toString();\r
+ int open = -1;\r
+ int close = -1;\r
+ int colon = -1;\r
+ for (int i=0; i < s.length(); i++) {\r
+ char c = s.charAt(i);\r
+ if (c == ':')\r
+ colon = i;\r
+ else if (c == '(')\r
+ open = i;\r
+ else if (c == ')')\r
+ close = i;\r
+ else if (c == '\n' && open != -1 && close != -1 && colon != -1 && \r
+ open < colon && colon < close) \r
+ {\r
+ String fileStr = s.substring(open + 1, colon);\r
+ if (fileStr.endsWith(".js")) {\r
+ String lineStr = s.substring(colon + 1, close);\r
+ try {\r
+ linep[0] = Integer.parseInt(lineStr);\r
+ return fileStr;\r
+ }\r
+ catch (NumberFormatException e) {\r
+ // fall through\r
+ }\r
+ }\r
+ open = close = colon = -1;\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ RegExpProxy getRegExpProxy() {\r
+ if (regExpProxy == null) {\r
+ try {\r
+ Class c = Class.forName(\r
+ "org.mozilla.javascript.regexp.RegExpImpl");\r
+ regExpProxy = (RegExpProxy) c.newInstance();\r
+ return regExpProxy;\r
+ } catch (ClassNotFoundException e) {\r
+ } catch (InstantiationException e) {\r
+ } catch (IllegalAccessException e) {\r
+ }\r
+ }\r
+ return regExpProxy;\r
+ }\r
+\r
+ private void newArrayHelper(Scriptable scope, Scriptable array) {\r
+ array.setParentScope(scope);\r
+ Object ctor = ScriptRuntime.getTopLevelProp(scope, "Array");\r
+ if (ctor != null && ctor instanceof Scriptable) {\r
+ Scriptable s = (Scriptable) ctor;\r
+ array.setPrototype((Scriptable) s.get("prototype", s));\r
+ }\r
+ }\r
+ \r
+ final boolean isVersionECMA1() {\r
+ return version == VERSION_DEFAULT || version >= VERSION_1_3;\r
+ }\r
+\r
+ /**\r
+ * Get the security context from the given class.\r
+ * <p>\r
+ * When some form of security check needs to be done, the class context\r
+ * must retrieved from the security manager to determine what class is\r
+ * requesting some form of privileged access. \r
+ * @since 1.4 release 2\r
+ */\r
+ Object getSecurityDomainFromClass(Class cl) {\r
+ if (cl == Interpreter.class)\r
+ return interpreterSecurityDomain;\r
+ return securitySupport.getSecurityDomain(cl);\r
+ }\r
+ \r
+ SecuritySupport getSecuritySupport() {\r
+ return securitySupport;\r
+ }\r
+ \r
+ Object getSecurityDomainForStackDepth(int depth) {\r
+ Object result = null;\r
+ if (securitySupport != null) {\r
+ Class[] classes = securitySupport.getClassContext();\r
+ if (classes != null) {\r
+ if (depth != -1) {\r
+ int depth1 = depth + 1;\r
+ result = getSecurityDomainFromClass(classes[depth1]);\r
+ } else {\r
+ for (int i=1; i < classes.length; i++) {\r
+ result = getSecurityDomainFromClass(classes[i]);\r
+ if (result != null)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (result != null)\r
+ return result;\r
+ if (requireSecurityDomain) \r
+ checkSecurityDomainRequired();\r
+ return null;\r
+ }\r
+\r
+ private static boolean requireSecurityDomain = false;\r
+ private static boolean resourceMissing = false;\r
+\r
+ final static String securityResourceName = "org.mozilla.javascript.resources.Security";\r
+ \r
+ final public static void checkSecurityDomainRequired() { }\r
+\r
+ public boolean isGeneratingDebugChanged() {\r
+ return generatingDebugChanged;\r
+ }\r
+ \r
+\r
+ /**\r
+ * Add a name to the list of names forcing the creation of real\r
+ * activation objects for functions.\r
+ *\r
+ * @param name the name of the object to add to the list\r
+ */\r
+ public void addActivationName(String name) {\r
+ if (activationNames == null) \r
+ activationNames = new Hashtable(5);\r
+ activationNames.put(name, name);\r
+ }\r
+\r
+ /**\r
+ * Check whether the name is in the list of names of objects\r
+ * forcing the creation of activation objects.\r
+ *\r
+ * @param name the name of the object to test\r
+ *\r
+ * @return true if an function activation object is needed.\r
+ */\r
+ public boolean isActivationNeeded(String name) {\r
+ if ("arguments".equals(name))\r
+ return true;\r
+ return activationNames != null && activationNames.containsKey(name);\r
+ }\r
+\r
+ /**\r
+ * Remove a name from the list of names forcing the creation of real\r
+ * activation objects for functions.\r
+ *\r
+ * @param name the name of the object to remove from the list\r
+ */\r
+ public void removeActivationName(String name) {\r
+ if (activationNames != null)\r
+ activationNames.remove(name);\r
+ }\r
+\r
+\r
+ static final boolean useJSObject = false;\r
+\r
+ /** \r
+ * The activation of the currently executing function or script. \r
+ */\r
+ NativeCall currentActivation;\r
+\r
+ // for Objects, Arrays to tag themselves as being printed out,\r
+ // so they don't print themselves out recursively.\r
+ Hashtable iterating;\r
+ \r
+ Object interpreterSecurityDomain;\r
+\r
+ int version;\r
+ int errorCount;\r
+ static boolean isCachingEnabled = true;\r
+ \r
+ private SecuritySupport securitySupport;\r
+ private ErrorReporter errorReporter;\r
+ private Thread currentThread;\r
+ private static Hashtable threadContexts = new Hashtable(11);\r
+ private RegExpProxy regExpProxy;\r
+ private Locale locale;\r
+ private boolean generatingDebug;\r
+ private boolean generatingDebugChanged;\r
+ private boolean generatingSource=true;\r
+ private boolean compileFunctionsWithDynamicScopeFlag;\r
+ private int optimizationLevel;\r
+ WrapHandler wrapHandler;\r
+ Debugger debugger;\r
+ DebuggableEngine debuggableEngine;\r
+ boolean inLineStepMode;\r
+ java.util.Stack frameStack; \r
+ private int enterCount;\r
+ private Object[] listeners;\r
+ private Hashtable hashtable;\r
+\r
+ /**\r
+ * This is the list of names of objects forcing the creation of\r
+ * function activation records.\r
+ */\r
+ private Hashtable activationNames;\r
+\r
+ // Private lock for static fields to avoid a possibility of denial\r
+ // of service via synchronized (Context.class) { while (true) {} }\r
+ private static final Object staticDataLock = new Object();\r
+ private static Object[] contextListeners;\r
+ public Function currentFunction;\r
+ Vector arrayCache = new Vector(10);\r
+\r
+ // For the interpreter to indicate line/source for error reports.\r
+ public int interpreterLine;\r
+ public String interpreterSourceFile;\r
+\r
+ public int stackDepth = 0;\r
+\r
+ // For instruction counting (interpreter only)\r
+ int instructionCount;\r
+ int instructionThreshold;\r
+}\r