gt:         if (!(script instanceof InterpretedFunction) ||
context: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
   *
   * This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
  // API class
  
  package org.mozilla.javascript;
  
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.io.*;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.net.URI;
  import java.net.URL;
  import java.util.*;
  import java.util.jar.Attributes;
  import java.util.jar.Manifest;
  
  import org.mozilla.javascript.ast.AstRoot;
  import org.mozilla.javascript.ast.ScriptNode;
  import org.mozilla.javascript.debug.DebuggableScript;
  import org.mozilla.javascript.debug.Debugger;
  import org.mozilla.javascript.xml.XMLLib;
  
  /**
   * This class represents the runtime context of an executing script.
   *
   * Before executing a script, an instance of Context must be created
   * and associated with the thread that will be executing the script.
   * The Context will be used to store information about the executing
   * of the script such as the call stack. Contexts are associated with
   * the current thread  using the {@link #call(ContextAction)}
   * or {@link #enter()} methods.<p>
   *
   * Different forms of script execution are supported. Scripts may be
   * evaluated from the source directly, or first compiled and then later
   * executed. Interactive execution is also supported.<p>
   *
   * Some aspects of script execution, such as type conversions and
   * object creation, may be accessed directly through methods of
   * Context.
   *
   * @see Scriptable
   * @author Norris Boyd
   * @author Brendan Eich
   */
  
  public class Context
  {
      /**
       * Language versions.
       *
       * All integral values are reserved for future version numbers.
       */
  
      /**
       * The unknown version.
       */
      public static final int VERSION_UNKNOWN =   -1;
  
      /**
       * The default version.
       */
      public static final int VERSION_DEFAULT =    0;
  
      /**
       * JavaScript 1.0
       */
      public static final int VERSION_1_0 =      100;
  
      /**
       * JavaScript 1.1
       */
      public static final int VERSION_1_1 =      110;
  
      /**
       * JavaScript 1.2
       */
      public static final int VERSION_1_2 =      120;
  
      /**
       * JavaScript 1.3
       */
      public static final int VERSION_1_3 =      130;
  
      /**
       * JavaScript 1.4
       */
      public static final int VERSION_1_4 =      140;
  
      /**
       * JavaScript 1.5
       */
      public static final int VERSION_1_5 =      150;
  
      /**
       * JavaScript 1.6
       */
      public static final int VERSION_1_6 =      160;
  
      /**
       * JavaScript 1.7
       */
      public static final int VERSION_1_7 =      170;
  
      /**
       * JavaScript 1.8
       */
      public static final int VERSION_1_8 =      180;
  
      /**
       * Controls behaviour of <tt>Date.prototype.getYear()</tt>.
       * If <tt>hasFeature(FEATURE_NON_ECMA_GET_YEAR)</tt> returns true,
       * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000.
       * The default behavior of {@link #hasFeature(int)} is always to subtruct
       * 1900 as rquired by ECMAScript B.2.4.
       */
      public static final int FEATURE_NON_ECMA_GET_YEAR = 1;
  
      /**
       * Control if member expression as function name extension is available.
       * If <tt>hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)</tt> returns
       * true, allow <tt>function memberExpression(args) { body }</tt> to be
       * syntax sugar for <tt>memberExpression = function(args) { body }</tt>,
       * when memberExpression is not a simple identifier.
       * See ECMAScript-262, section 11.2 for definition of memberExpression.
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME = 2;
  
      /**
       * Control if reserved keywords are treated as identifiers.
       * If <tt>hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER)</tt> returns true,
       * treat future reserved keyword (see  Ecma-262, section 7.5.3) as ordinary
       * identifiers but warn about this usage.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER = 3;
  
      /**
       * Control if <tt>toString()</tt> should returns the same result
       * as  <tt>toSource()</tt> when applied to objects and arrays.
       * If <tt>hasFeature(FEATURE_TO_STRING_AS_SOURCE)</tt> returns true,
       * calling <tt>toString()</tt> on JS objects gives the same result as
       * calling <tt>toSource()</tt>. That is it returns JS source with code
       * to create an object with all enumeratable fields of the original object
       * instead of printing <tt>[object <i>result of
       * {@link Scriptable#getClassName()}</i>]</tt>.
       * <p>
       * By default {@link #hasFeature(int)} returns true only if
       * the current JS version is set to {@link #VERSION_1_2}.
       */
      public static final int FEATURE_TO_STRING_AS_SOURCE = 4;
  
      /**
       * Control if properties <tt>__proto__</tt> and <tt>__parent__</tt>
       * are treated specially.
       * If <tt>hasFeature(FEATURE_PARENT_PROTO_PROPERTIES)</tt> returns true,
       * treat <tt>__parent__</tt> and <tt>__proto__</tt> as special properties.
       * <p>
       * The properties allow to query and set scope and prototype chains for the
       * objects. The special meaning of the properties is available
       * only when they are used as the right hand side of the dot operator.
       * For example, while <tt>x.__proto__ = y</tt> changes the prototype
       * chain of the object <tt>x</tt> to point to <tt>y</tt>,
       * <tt>x["__proto__"] = y</tt> simply assigns a new value to the property
       * <tt>__proto__</tt> in <tt>x</tt> even when the feature is on.
       *
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_PARENT_PROTO_PROPERTIES = 5;
  
      /**
       * @deprecated In previous releases, this name was given to
       * FEATURE_PARENT_PROTO_PROPERTIES.
       */
      @Deprecated
      public static final int FEATURE_PARENT_PROTO_PROPRTIES = 5;
  
      /**
       * Control if support for E4X(ECMAScript for XML) extension is available.
       * If hasFeature(FEATURE_E4X) returns true, the XML syntax is available.
       * <p>
       * By default {@link #hasFeature(int)} returns true if
       * the current JS version is set to {@link #VERSION_DEFAULT}
       * or is at least {@link #VERSION_1_6}.
       * @since 1.6 Release 1
       */
      public static final int FEATURE_E4X = 6;
  
      /**
       * Control if dynamic scope should be used for name access.
       * If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup
       * during name resolution will use the top scope of the script or function
       * which is at the top of JS execution stack instead of the top scope of the
       * script or function from the current stack frame if the top scope of
       * the top stack frame contains the top scope of the current stack frame
       * on its prototype chain.
       * <p>
       * This is useful to define shared scope containing functions that can
       * be called from scripts and functions using private scopes.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.6 Release 1
       */
      public static final int FEATURE_DYNAMIC_SCOPE = 7;
  
      /**
       * Control if strict variable mode is enabled.
       * When the feature is on Rhino reports runtime errors if assignment
       * to a global variable that does not exist is executed. When the feature
       * is off such assignments create a new variable in the global scope as
       * required by ECMA 262.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.6 Release 1
       */
      public static final int FEATURE_STRICT_VARS = 8;
  
      /**
       * Control if strict eval mode is enabled.
       * When the feature is on Rhino reports runtime errors if non-string
       * argument is passed to the eval function. When the feature is off
       * eval simply return non-string argument as is without performing any
       * evaluation as required by ECMA 262.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.6 Release 1
       */
      public static final int FEATURE_STRICT_EVAL = 9;
  
      /**
       * When the feature is on Rhino will add a "fileName" and "lineNumber"
       * properties to Error objects automatically. When the feature is off, you
       * have to explicitly pass them as the second and third argument to the
       * Error constructor. Note that neither behavior is fully ECMA 262
       * compliant (as 262 doesn't specify a three-arg constructor), but keeping
       * the feature off results in Error objects that don't have
       * additional non-ECMA properties when constructed using the ECMA-defined
       * single-arg constructor and is thus desirable if a stricter ECMA
       * compliance is desired, specifically adherence to the point 15.11.5. of
       * the standard.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.6 Release 6
       */
      public static final int FEATURE_LOCATION_INFORMATION_IN_ERROR = 10;
  
      /**
       * Controls whether JS 1.5 'strict mode' is enabled.
       * When the feature is on, Rhino reports more than a dozen different
       * warnings.  When the feature is off, these warnings are not generated.
       * FEATURE_STRICT_MODE implies FEATURE_STRICT_VARS and FEATURE_STRICT_EVAL.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.6 Release 6
       */
      public static final int FEATURE_STRICT_MODE = 11;
  
      /**
       * Controls whether a warning should be treated as an error.
       * @since 1.6 Release 6
       */
      public static final int FEATURE_WARNING_AS_ERROR = 12;
  
      /**
       * Enables enhanced access to Java.
       * Specifically, controls whether private and protected members can be
       * accessed, and whether scripts can catch all Java exceptions.
       * <p>
       * Note that this feature should only be enabled for trusted scripts.
       * <p>
       * By default {@link #hasFeature(int)} returns false.
       * @since 1.7 Release 1
       */
      public static final int FEATURE_ENHANCED_JAVA_ACCESS = 13;
  
      /**
       * Enables access to JavaScript features from ECMAscript 6 that are present in
       * JavaScript engines that do not yet support version 6, such as V8.
       * This includes support for typed arrays. Default is true.
       * @since 1.7 Release 3
       */
      public static final int FEATURE_V8_EXTENSIONS = 14;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * The same web browser (e.g. FF) may allow setting read-only property, 
       * ignores setting the read-only property, or even throw an exception.
       *
       * So, by having this feature, ScriptableObject itself is asked throw
       * {@link ScriptableObject#isReadOnlySettable} whether to allow, ignore or throw an exception.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_ASK_OBJECT_TO_WRITE_READONLY = 100;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       * Indicates if a JavaScript catch statement can catch Java exceptions
       * (exceptions occurring in host objects).
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_HTMLUNIT_JS_CATCH_JAVA_EXCEPTION = 101;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Is the default value of {@link Arguments} "Object" or "Arguments"
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_ARGUMENTS_IS_OBJECT = 102;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * When setting the function name to call, call thisObject.setter.
       *
       * This is needed for something like "function onclick() {onclick = null}"
       *
       * Implemented by transforming it into "function onclick() {<b>this.</b>onclick = null}"
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_FUNCTION_NULL_SETTER = 103;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Whether the "someFunc.arguments" is a read-only view of the function argument
       * or the real arguments.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_FN_ARGUMENTS_IS_RO_VIEW = 104;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that 'eval' function should have access to the local function scope.
       *
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_HTMLUNIT_EVAL_LOCAL_SCOPE = 105;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that 'exception' (technically NativeError) exposes "stack" property.
       *
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_HTMLUNIT_ERROR_STACK = 106;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that ".constructor" property is defined for all {@link ScriptableObject}s.
       *
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_HTMLUNIT_CONSTRUCTOR = 107;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that function can be defined as
       * <code>function object.property() {}</code> instead of <code>object.property = function() {}</code>.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_FUNCTION_OBJECT_METHOD = 108;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that function is defined even before its declaration, inside a block.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_FUNCTION_DECLARED_FORWARD_IN_BLOCK = 109;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that parseInt() should have radix 10 by default.
       *
       * By default {@link #hasFeature(int)} returns true.
       */
      public static final int FEATURE_HTMLUNIT_PARSE_INT_RADIX_10 = 110;
  
      /**
       * Special to HtmlUnit's Rhino fork.
       *
       * Indicates that for(x in []) should enumerate the numbers first.
       *
       * By default {@link #hasFeature(int)} returns false.
       */
      public static final int FEATURE_HTMLUNIT_ENUM_NUMBERS_FIRST = 111;
  
      public static final String languageVersionProperty = "language version";
      public static final String errorReporterProperty   = "error reporter";
  
      /**
       * Convenient value to use as zero-length array of objects.
       */
      public static final Object[] emptyArgs = ScriptRuntime.emptyArgs;
  
      /**
       * Creates a new Context. The context will be associated with the {@link
       * ContextFactory#getGlobal() global context factory}.
       *
       * Note that the Context must be associated with a thread before
       * it can be used to execute a script.
       * @deprecated this constructor is deprecated because it creates a
       * dependency on a static singleton context factory. Use
       * {@link ContextFactory#enter()} or
       * {@link ContextFactory#call(ContextAction)} instead. If you subclass
       * this class, consider using {@link #Context(ContextFactory)} constructor
       * instead in the subclasses' constructors.
       */
      @Deprecated
      public Context()
      {
          this(ContextFactory.getGlobal());
      }
  
      /**
       * Creates a new context. Provided as a preferred super constructor for
       * subclasses in place of the deprecated default public constructor.
       * @param factory the context factory associated with this context (most
       * likely, the one that created the context). Can not be null. The context
       * features are inherited from the factory, and the context will also
       * otherwise use its factory's services.
       * @throws IllegalArgumentException if factory parameter is null.
       */
      protected Context(ContextFactory factory)
      {
          if(factory == null) {
              throw new IllegalArgumentException("factory == null");
          }
          this.factory = factory;
          version = VERSION_DEFAULT;
          optimizationLevel = codegenClass != null ? 0 : -1;
          maximumInterpreterStackDepth = Integer.MAX_VALUE;
      }
  
      /**
       * Get the current Context.
       *
       * The current Context is per-thread; this method looks up
       * the Context associated with the current thread. <p>
       *
       * @return the Context associated with the current thread, or
       *         null if no context is associated with the current
       *         thread.
       * @see ContextFactory#enterContext()
       * @see ContextFactory#call(ContextAction)
       */
      public static Context getCurrentContext()
      {
          Object helper = VMBridge.instance.getThreadContextHelper();
          return VMBridge.instance.getContext(helper);
      }
  
      /**
       * Same as calling {@link ContextFactory#enterContext()} on the global
       * ContextFactory instance.
       * @return a Context associated with the current thread
       * @see #getCurrentContext()
       * @see #exit()
       * @see #call(ContextAction)
       */
      public static Context enter()
      {
          return enter(null);
      }
  
      /**
       * Get a Context associated with the current thread, using
       * the given Context if need be.
       * <p>
       * The same as <code>enter()</code> except that <code>cx</code>
       * is associated with the current thread and returned if
       * the current thread has no associated context and <code>cx</code>
       * is not associated with any other thread.
       * @param cx a Context to associate with the thread if possible
       * @return a Context associated with the current thread
       * @deprecated use {@link ContextFactory#enterContext(Context)} instead as
       * this method relies on usage of a static singleton "global" ContextFactory.
       * @see ContextFactory#enterContext(Context)
       * @see ContextFactory#call(ContextAction)
       */
      @Deprecated
      public static Context enter(Context cx)
      {
          return enter(cx, ContextFactory.getGlobal());
      }
  
      static final Context enter(Context cx, ContextFactory factory)
      {
          Object helper = VMBridge.instance.getThreadContextHelper();
          Context old = VMBridge.instance.getContext(helper);
          if (old != null) {
              cx = old;
          } else {
              if (cx == null) {
                  cx = factory.makeContext();
                  if (cx.enterCount != 0) {
                      throw new IllegalStateException("factory.makeContext() returned Context instance already associated with some thread");
                  }
                  factory.onContextCreated(cx);
                  if (factory.isSealed() && !cx.isSealed()) {
                      cx.seal(null);
                  }
              } else {
                  if (cx.enterCount != 0) {
                      throw new IllegalStateException("can not use Context instance already associated with some thread");
                  }
              }
              VMBridge.instance.setContext(helper, cx);
          }
          ++cx.enterCount;
          return cx;
       }
  
      /**
       * Exit a block of code requiring a Context.
       *
       * Calling <code>exit()</code> will remove the association between
       * the current thread and a Context if the prior call to
       * {@link ContextFactory#enterContext()} on this thread newly associated a
       * Context with this thread. Once the current thread no longer has an
       * associated Context, it cannot be used to execute JavaScript until it is
       * again associated with a Context.
       * @see ContextFactory#enterContext()
       */
      public static void exit()
      {
          Object helper = VMBridge.instance.getThreadContextHelper();
          Context cx = VMBridge.instance.getContext(helper);
          if (cx == null) {
              throw new IllegalStateException(
                  "Calling Context.exit without previous Context.enter");
          }
          if (cx.enterCount < 1) Kit.codeBug();
          if (--cx.enterCount == 0) {
              VMBridge.instance.setContext(helper, null);
              cx.factory.onContextReleased(cx);
          }
      }
  
      /**
       * Call {@link ContextAction#run(Context cx)}
       * using the Context instance associated with the current thread.
       * If no Context is associated with the thread, then
       * <tt>ContextFactory.getGlobal().makeContext()</tt> will be called to
       * construct new Context instance. The instance will be temporary
       * associated with the thread during call to
       * {@link ContextAction#run(Context)}.
       * @deprecated use {@link ContextFactory#call(ContextAction)} instead as
       * this method relies on usage of a static singleton "global"
       * ContextFactory.
       * @return The result of {@link ContextAction#run(Context)}.
       */
      @Deprecated
      public static Object call(ContextAction action)
      {
          return call(ContextFactory.getGlobal(), action);
      }
  
      /**
       * Call {@link
       * Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
       *               Object[] args)}
       * using the Context instance associated with the current thread.
       * If no Context is associated with the thread, then
       * {@link ContextFactory#makeContext()} will be called to construct
       * new Context instance. The instance will be temporary associated
       * with the thread during call to {@link ContextAction#run(Context)}.
       * <p>
       * It is allowed but not advisable to use null for <tt>factory</tt>
       * argument in which case the global static singleton ContextFactory
       * instance will be used to create new context instances.
       * @see ContextFactory#call(ContextAction)
       */
      public static Object call(ContextFactory factory, final Callable callable,
                                final Scriptable scope, final Scriptable thisObj,
                                final Object[] args)
      {
          if(factory == null) {
              factory = ContextFactory.getGlobal();
          }
          return call(factory, new ContextAction() {
              public Object run(Context cx) {
                  return callable.call(cx, scope, thisObj, args);
              }
          });
      }
  
      /**
       * The method implements {@link ContextFactory#call(ContextAction)} logic.
       */
      static Object call(ContextFactory factory, ContextAction action) {
          Context cx = enter(null, factory);
          try {
              return action.run(cx);
          }
          finally {
              exit();
          }
      }
  
      /**
       * @deprecated
       * @see ContextFactory#addListener(org.mozilla.javascript.ContextFactory.Listener)
       * @see ContextFactory#getGlobal()
       */
      @Deprecated
      public static void addContextListener(ContextListener listener)
      {
          // Special workaround for the debugger
          String DBG = "org.mozilla.javascript.tools.debugger.Main";
          if (DBG.equals(listener.getClass().getName())) {
              Class<?> cl = listener.getClass();
              Class<?> factoryClass = Kit.classOrNull(
                  "org.mozilla.javascript.ContextFactory");
              Class<?>[] sig = { factoryClass };
              Object[] args = { ContextFactory.getGlobal() };
              try {
                  Method m = cl.getMethod("attachTo", sig);
                  m.invoke(listener, args);
              } catch (Exception ex) {
                  RuntimeException rex = new RuntimeException();
                  Kit.initCause(rex, ex);
                  throw rex;
              }
              return;
          }
  
          ContextFactory.getGlobal().addListener(listener);
      }
  
      /**
       * @deprecated
       * @see ContextFactory#removeListener(org.mozilla.javascript.ContextFactory.Listener)
       * @see ContextFactory#getGlobal()
       */
      @Deprecated
      public static void removeContextListener(ContextListener listener)
      {
          ContextFactory.getGlobal().addListener(listener);
      }
  
      /**
       * Return {@link ContextFactory} instance used to create this Context.
       */
      public final ContextFactory getFactory()
      {
          return factory;
      }
  
      /**
       * Checks if this is a sealed Context. A sealed Context instance does not
       * allow to modify any of its properties and will throw an exception
       * on any such attempt.
       * @see #seal(Object sealKey)
       */
      public final boolean isSealed()
      {
          return sealed;
      }
  
      /**
       * Seal this Context object so any attempt to modify any of its properties
       * including calling {@link #enter()} and {@link #exit()} methods will
       * throw an exception.
       * <p>
       * If <tt>sealKey</tt> is not null, calling
       * {@link #unseal(Object sealKey)} with the same key unseals
       * the object. If <tt>sealKey</tt> is null, unsealing is no longer possible.
       *
       * @see #isSealed()
       * @see #unseal(Object)
       */
      public final void seal(Object sealKey)
      {
          if (sealed) onSealedMutation();
          sealed = true;
          this.sealKey = sealKey;
      }
  
      /**
       * Unseal previously sealed Context object.
       * The <tt>sealKey</tt> argument should not be null and should match
       * <tt>sealKey</tt> suplied with the last call to
       * {@link #seal(Object)} or an exception will be thrown.
       *
       * @see #isSealed()
       * @see #seal(Object sealKey)
       */
      public final void unseal(Object sealKey)
      {
          if (sealKey == null) throw new IllegalArgumentException();
          if (this.sealKey != sealKey) throw new IllegalArgumentException();
          if (!sealed) throw new IllegalStateException();
          sealed = false;
          this.sealKey = null;
      }
  
      static void onSealedMutation()
      {
          throw new IllegalStateException();
      }
  
      /**
       * Get the current language version.
       * <p>
       * The language version number affects JavaScript semantics as detailed
       * in the overview documentation.
       *
       * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
       */
      public final int getLanguageVersion()
      {
         return version;
      }
  
      /**
       * Set the language version.
       *
       * <p>
       * Setting the language version will affect functions and scripts compiled
       * subsequently. See the overview documentation for version-specific
       * behavior.
       *
       * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
       */
      public void setLanguageVersion(int version)
      {
          if (sealed) onSealedMutation();
          checkLanguageVersion(version);
          Object listeners = propertyListeners;
          if (listeners != null && version != this.version) {
              firePropertyChangeImpl(listeners, languageVersionProperty,
                                 Integer.valueOf(this.version),
                                 Integer.valueOf(version));
          }
          this.version = version;
      }
  
      public static boolean isValidLanguageVersion(int version)
      {
          switch (version) {
              case VERSION_DEFAULT:
              case VERSION_1_0:
              case VERSION_1_1:
              case VERSION_1_2:
              case VERSION_1_3:
              case VERSION_1_4:
              case VERSION_1_5:
              case VERSION_1_6:
              case VERSION_1_7:
              case VERSION_1_8:
                  return true;
          }
          return false;
      }
  
      public static void checkLanguageVersion(int version)
      {
          if (isValidLanguageVersion(version)) {
              return;
          }
          throw new IllegalArgumentException("Bad language version: "+version);
      }
  
      /**
       * Get the implementation version.
       *
       * <p>
       * The implementation version is of the form
       * <pre>
       *    "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
       * </pre>
       * where <i>name</i> is the name of the product, <i>langVer</i> is
       * the language version, <i>relNum</i> is the release number, and
       * <i>date</i> is the release date for that specific
       * release in the form "yyyy mm dd".
       *
       * @return a string that encodes the product, language version, release
       *         number, and date.
       */
      public final String getImplementationVersion()
      {
          if (implementationVersion == null) {
              Enumeration<URL> urls;
              try {
                  urls = Context.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
              } catch (IOException ioe) {
                  return null;
              }
  
              // There will be many manifests in the world -- enumerate all of them until we find the right one.
              while (urls.hasMoreElements()) {
                  URL metaUrl = urls.nextElement();
                  InputStream is = null;
                  try {
                      is = metaUrl.openStream();
                      Manifest mf = new Manifest(is);
                      Attributes attrs = mf.getMainAttributes();
                      if ("Mozilla Rhino".equals(attrs.getValue("Implementation-Title"))) {
                          implementationVersion =
                              "Rhino " + attrs.getValue("Implementation-Version") + " " + attrs.getValue("Built-Date").replaceAll("-", " ");
                          return implementationVersion;
                      }
                  } catch (IOException e) {
                      // Ignore this unlikely event
                  } finally {
                      try {
                          if (is != null) is.close();
                      } catch (IOException e) {
                          // Ignore this even unlikelier event
                      }
                  }
              }
          }
  
          return implementationVersion;
      }
  
      /**
       * Get the current error reporter.
       *
       * @see org.mozilla.javascript.ErrorReporter
       */
      public final ErrorReporter getErrorReporter()
      {
          if (errorReporter == null) {
              return DefaultErrorReporter.instance;
          }
          return errorReporter;
      }
  
      /**
       * Change the current error reporter.
       *
       * @return the previous error reporter
       * @see org.mozilla.javascript.ErrorReporter
       */
      public final ErrorReporter setErrorReporter(ErrorReporter reporter)
      {
          if (sealed) onSealedMutation();
          if (reporter == null) throw new IllegalArgumentException();
          ErrorReporter old = getErrorReporter();
          if (reporter == old) {
              return old;
          }
          Object listeners = propertyListeners;
          if (listeners != null) {
              firePropertyChangeImpl(listeners, errorReporterProperty,
                                     old, reporter);
          }
          this.errorReporter = reporter;
          return old;
      }
  
      /**
       * Get the current locale.  Returns the default locale if none has
       * been set.
       *
       * @see java.util.Locale
       */
  
      public final Locale getLocale()
      {
          if (locale == null)
              locale = Locale.getDefault();
          return locale;
      }
  
      /**
       * Set the current locale.
       *
       * @see java.util.Locale
       */
      public final Locale setLocale(Locale loc)
      {
          if (sealed) onSealedMutation();
          Locale result = locale;
          locale = loc;
          return result;
      }
  
      /**
       * Register an object to receive notifications when a bound property
       * has changed
       * @see java.beans.PropertyChangeEvent
       * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
       * @param l the listener
       */
      public final void addPropertyChangeListener(PropertyChangeListener l)
      {
          if (sealed) onSealedMutation();
          propertyListeners = Kit.addListener(propertyListeners, l);
      }
  
      /**
       * Remove an object from the list of objects registered to receive
       * notification of changes to a bounded property
       * @see java.beans.PropertyChangeEvent
       * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
       * @param l the listener
       */
      public final void removePropertyChangeListener(PropertyChangeListener l)
      {
          if (sealed) onSealedMutation();
          propertyListeners = Kit.removeListener(propertyListeners, l);
      }
  
      /**
       * Notify any registered listeners that a bounded property has changed
       * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
       * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
       * @see java.beans.PropertyChangeListener
       * @see java.beans.PropertyChangeEvent
       * @param  property  the bound property
       * @param  oldValue  the old value
       * @param  newValue   the new value
       */
      final void firePropertyChange(String property, Object oldValue,
                                    Object newValue)
      {
          Object listeners = propertyListeners;
          if (listeners != null) {
              firePropertyChangeImpl(listeners, property, oldValue, newValue);
          }
      }
  
      private void firePropertyChangeImpl(Object listeners, String property,
                                          Object oldValue, Object newValue)
      {
          for (int i = 0; ; ++i) {
              Object l = Kit.getListener(listeners, i);
              if (l == null)
                  break;
              if (l instanceof PropertyChangeListener) {
                  PropertyChangeListener pcl = (PropertyChangeListener)l;
                  pcl.propertyChange(new PropertyChangeEvent(
                      this, property, oldValue, newValue));
              }
          }
      }
  
      /**
       * Report a warning using the error reporter for the current thread.
       *
       * @param message the warning message to report
       * @param sourceName a string describing the source, such as a filename
       * @param lineno the starting line number
       * @param lineSource the text of the line (may be null)
       * @param lineOffset the offset into lineSource where problem was detected
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static void reportWarning(String message, String sourceName,
                                       int lineno, String lineSource,
                                       int lineOffset)
      {
          Context cx = Context.getContext();
          if (cx.hasFeature(FEATURE_WARNING_AS_ERROR))
              reportError(message, sourceName, lineno, lineSource, lineOffset);
          else
              cx.getErrorReporter().warning(message, sourceName, lineno,
                                            lineSource, lineOffset);
      }
  
      /**
       * Report a warning using the error reporter for the current thread.
       *
       * @param message the warning message to report
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static void reportWarning(String message)
      {
          int[] linep = { 0 };
          String filename = getSourcePositionFromStack(linep);
          Context.reportWarning(message, filename, linep[0], null, 0);
      }
  
      public static void reportWarning(String message, Throwable t)
      {
          int[] linep = { 0 };
          String filename = getSourcePositionFromStack(linep);
          Writer sw = new StringWriter();
          PrintWriter pw = new PrintWriter(sw);
          pw.println(message);
          t.printStackTrace(pw);
          pw.flush();
          Context.reportWarning(sw.toString(), filename, linep[0], null, 0);
      }
  
      /**
       * Report an error using the error reporter for the current thread.
       *
       * @param message the error message to report
       * @param sourceName a string describing the source, such as a filename
       * @param lineno the starting line number
       * @param lineSource the text of the line (may be null)
       * @param lineOffset the offset into lineSource where problem was detected
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static void reportError(String message, String sourceName,
                                     int lineno, String lineSource,
                                     int lineOffset)
      {
          Context cx = getCurrentContext();
          if (cx != null) {
              cx.getErrorReporter().error(message, sourceName, lineno,
                                          lineSource, lineOffset);
          } else {
              throw new EvaluatorException(message, sourceName, lineno,
                                           lineSource, lineOffset);
          }
      }
  
      /**
       * Report an error using the error reporter for the current thread.
       *
       * @param message the error message to report
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static void reportError(String message)
      {
          int[] linep = { 0 };
          String filename = getSourcePositionFromStack(linep);
          Context.reportError(message, filename, linep[0], null, 0);
      }
  
      /**
       * Report a runtime error using the error reporter for the current thread.
       *
       * @param message the error message to report
       * @param sourceName a string describing the source, such as a filename
       * @param lineno the starting line number
       * @param lineSource the text of the line (may be null)
       * @param lineOffset the offset into lineSource where problem was detected
       * @return a runtime exception that will be thrown to terminate the
       *         execution of the script
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static EvaluatorException reportRuntimeError(String message,
                                                          String sourceName,
                                                          int lineno,
                                                          String lineSource,
                                                          int lineOffset)
      {
          Context cx = getCurrentContext();
          if (cx != null) {
              return cx.getErrorReporter().
                              runtimeError(message, sourceName, lineno,
                                           lineSource, lineOffset);
          } else {
              throw new EvaluatorException(message, sourceName, lineno,
                                           lineSource, lineOffset);
          }
      }
  
      static EvaluatorException reportRuntimeError0(String messageId)
      {
          String msg = ScriptRuntime.getMessage0(messageId);
          return reportRuntimeError(msg);
      }
  
      static EvaluatorException reportRuntimeError1(String messageId,
                                                    Object arg1)
      {
          String msg = ScriptRuntime.getMessage1(messageId, arg1);
          return reportRuntimeError(msg);
      }
  
      static EvaluatorException reportRuntimeError2(String messageId,
                                                    Object arg1, Object arg2)
      {
          String msg = ScriptRuntime.getMessage2(messageId, arg1, arg2);
          return reportRuntimeError(msg);
      }
  
      static EvaluatorException reportRuntimeError3(String messageId,
                                                    Object arg1, Object arg2,
                                                    Object arg3)
      {
          String msg = ScriptRuntime.getMessage3(messageId, arg1, arg2, arg3);
          return reportRuntimeError(msg);
      }
  
      static EvaluatorException reportRuntimeError4(String messageId,
                                                    Object arg1, Object arg2,
                                                    Object arg3, Object arg4)
      {
          String msg
              = ScriptRuntime.getMessage4(messageId, arg1, arg2, arg3, arg4);
          return reportRuntimeError(msg);
      }
  
      /**
       * Report a runtime error using the error reporter for the current thread.
       *
       * @param message the error message to report
       * @see org.mozilla.javascript.ErrorReporter
       */
      public static EvaluatorException reportRuntimeError(String message)
      {
          int[] linep = { 0 };
          String filename = getSourcePositionFromStack(linep);
          return Context.reportRuntimeError(message, filename, linep[0], null, 0);
      }
  
      /**
       * Initialize the standard objects.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.
       *
       * @return the initialized scope
       */
      public final ScriptableObject initStandardObjects()
      {
          return initStandardObjects(null, false);
      }
  
      /**
       * Initialize the standard objects, leaving out those that offer access directly
       * to Java classes. This sets up "scope" to have access to all the standard
       * JavaScript classes, but does not create global objects for any top-level
       * Java packages. In addition, the "Packages," "JavaAdapter," and
       * "JavaImporter" classes, and the "getClass" function, are not
       * initialized.
       *
       * The result of this function is a scope that may be safely used in a "sandbox"
       * environment where it is not desirable to give access to Java code from JavaScript.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.
       *
       * @return the initialized scope
       */
      public final ScriptableObject initSafeStandardObjects()
      {
          return initSafeStandardObjects(null, false);
      }
  
      /**
       * Initialize the standard objects.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.
       *
       * @param scope the scope to initialize, or null, in which case a new
       *        object will be created to serve as the scope
       * @return the initialized scope. The method returns the value of the scope
       *         argument if it is not null or newly allocated scope object which
       *         is an instance {@link ScriptableObject}.
       */
      public final Scriptable initStandardObjects(ScriptableObject scope)
      {
          return initStandardObjects(scope, false);
      }
  
      /**
       * Initialize the standard objects, leaving out those that offer access directly
       * to Java classes. This sets up "scope" to have access to all the standard
       * JavaScript classes, but does not create global objects for any top-level
       * Java packages. In addition, the "Packages," "JavaAdapter," and
       * "JavaImporter" classes, and the "getClass" function, are not
       * initialized.
       *
       * The result of this function is a scope that may be safely used in a "sandbox"
       * environment where it is not desirable to give access to Java code from JavaScript.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.
       *
       * @param scope the scope to initialize, or null, in which case a new
       *        object will be created to serve as the scope
       * @return the initialized scope. The method returns the value of the scope
       *         argument if it is not null or newly allocated scope object which
       *         is an instance {@link ScriptableObject}.
       */
      public final Scriptable initSafeStandardObjects(ScriptableObject scope)
      {
          return initSafeStandardObjects(scope, false);
      }
  
      /**
       * Initialize the standard objects.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.<p>
       *
       * This form of the method also allows for creating "sealed" standard
       * objects. An object that is sealed cannot have properties added, changed,
       * or removed. This is useful to create a "superglobal" that can be shared
       * among several top-level objects. Note that sealing is not allowed in
       * the current ECMA/ISO language specification, but is likely for
       * the next version.
       *
       * @param scope the scope to initialize, or null, in which case a new
       *        object will be created to serve as the scope
       * @param sealed whether or not to create sealed standard objects that
       *        cannot be modified.
       * @return the initialized scope. The method returns the value of the scope
       *         argument if it is not null or newly allocated scope object.
       * @since 1.4R3
       */
      public ScriptableObject initStandardObjects(ScriptableObject scope,
                                                  boolean sealed)
      {
          return ScriptRuntime.initStandardObjects(this, scope, sealed);
      }
  
      /**
       * Initialize the standard objects, leaving out those that offer access directly
       * to Java classes. This sets up "scope" to have access to all the standard
       * JavaScript classes, but does not create global objects for any top-level
       * Java packages. In addition, the "Packages," "JavaAdapter," and
       * "JavaImporter" classes, and the "getClass" function, are not
       * initialized.
       *
       * The result of this function is a scope that may be safely used in a "sandbox"
       * environment where it is not desirable to give access to Java code from JavaScript.
       *
       * Creates instances of the standard objects and their constructors
       * (Object, String, Number, Date, etc.), setting up 'scope' to act
       * as a global object as in ECMA 15.1.<p>
       *
       * This method must be called to initialize a scope before scripts
       * can be evaluated in that scope.<p>
       *
       * This method does not affect the Context it is called upon.<p>
       *
       * This form of the method also allows for creating "sealed" standard
       * objects. An object that is sealed cannot have properties added, changed,
       * or removed. This is useful to create a "superglobal" that can be shared
       * among several top-level objects. Note that sealing is not allowed in
       * the current ECMA/ISO language specification, but is likely for
       * the next version.
       *
       * @param scope the scope to initialize, or null, in which case a new
       *        object will be created to serve as the scope
       * @param sealed whether or not to create sealed standard objects that
       *        cannot be modified.
       * @return the initialized scope. The method returns the value of the scope
       *         argument if it is not null or newly allocated scope object.
       * @since 1.7.6
       */
      public ScriptableObject initSafeStandardObjects(ScriptableObject scope,
                                                      boolean sealed)
      {
          return ScriptRuntime.initSafeStandardObjects(this, scope, sealed);
      }
  
      /**
       * Get the singleton object that represents the JavaScript Undefined value.
       */
      public static Object getUndefinedValue()
      {
          return Undefined.instance;
      }
  
      /**
       * Evaluate a JavaScript source string.
       *
       * The provided source name and line number are used for error messages
       * and for producing debug information.
       *
       * @param scope the scope to execute in
       * @param source the JavaScript source
       * @param sourceName a string describing the source, such as a filename
       * @param lineno the starting line number
       * @param securityDomain an arbitrary object that specifies security
       *        information about the origin or owner of the script. For
       *        implementations that don't care about security, this value
       *        may be null.
       * @return the result of evaluating the string
       * @see org.mozilla.javascript.SecurityController
       */
      public final Object evaluateString(Scriptable scope, String source,
                                         String sourceName, int lineno,
                                         Object securityDomain)
      {
          Script script = compileString(source, sourceName, lineno,
                                        securityDomain);
          if (script != null) {
              return script.exec(this, scope);
          } else {
              return null;
          }
      }
  
      /**
       * Evaluate a reader as JavaScript source.
       *
       * All characters of the reader are consumed.
       *
       * @param scope the scope to execute in
       * @param in the Reader to get JavaScript source from
       * @param sourceName a string describing the source, such as a filename
       * @param lineno the starting line number
       * @param securityDomain an arbitrary object that specifies security
       *        information about the origin or owner of the script. For
       *        implementations that don't care about security, this value
       *        may be null.
       * @return the result of evaluating the source
       *
       * @exception IOException if an IOException was generated by the Reader
       */
      public final Object evaluateReader(Scriptable scope, Reader in,
                                         String sourceName, int lineno,
                                         Object securityDomain)
          throws IOException
      {
          Script script = compileReader(scope, in, sourceName, lineno,
                                        securityDomain);
          if (script != null) {
              return script.exec(this, scope);
          } else {
              return null;
          }
      }
  
      /**
       * Execute script that may pause execution by capturing a continuation.
       * Caller must be prepared to catch a ContinuationPending exception
       * and resume execution by calling
       * {@link #resumeContinuation(Object, Scriptable, Object)}.
       * @param script The script to execute. Script must have been compiled
       *      with interpreted mode (optimization level -1)
       * @param scope The scope to execute the script against
       * @throws ContinuationPending if the script calls a function that results
       *      in a call to {@link #captureContinuation()}
       * @since 1.7 Release 2
       */
      public Object executeScriptWithContinuations(Script script,
              Scriptable scope)
          throws ContinuationPending
      {
  