@Override
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    final RhinoCompiledScript that = (RhinoCompiledScript) o;

    return compiledScript.equals(that.compiledScript) && engine.equals(that.engine);
  }
  /**
   * Get the default value of the object with a given hint. The hints are String.class for type
   * String, Number.class for type Number, Scriptable.class for type Object, and Boolean.class for
   * type Boolean.
   *
   * <p>A <code>hint</code> of null means "no hint".
   *
   * <p>See ECMA 8.6.2.6.
   *
   * @param hint the type hint
   * @return the default value
   */
  public Object getDefaultValue(Class<?> typeHint) {
    for (int i = 0; i < 2; i++) {
      boolean tryToString;
      if (typeHint == ScriptRuntime.StringClass) {
        tryToString = (i == 0);
      } else {
        tryToString = (i == 1);
      }

      String methodName;
      Object[] args;
      if (tryToString) {
        methodName = "toString";
        args = ScriptRuntime.emptyArgs;
      } else {
        methodName = "valueOf";
        args = new Object[1];
        String hint;
        if (typeHint == null) {
          hint = "undefined";
        } else if (typeHint == ScriptRuntime.StringClass) {
          hint = "string";
        } else if (typeHint == ScriptRuntime.ScriptableClass) {
          hint = "object";
        } else if (typeHint == ScriptRuntime.FunctionClass) {
          hint = "function";
        } else if (typeHint == ScriptRuntime.BooleanClass || typeHint == Boolean.TYPE) {
          hint = "boolean";
        } else if (typeHint == ScriptRuntime.NumberClass
            || typeHint == ScriptRuntime.ByteClass
            || typeHint == Byte.TYPE
            || typeHint == ScriptRuntime.ShortClass
            || typeHint == Short.TYPE
            || typeHint == ScriptRuntime.IntegerClass
            || typeHint == Integer.TYPE
            || typeHint == ScriptRuntime.FloatClass
            || typeHint == Float.TYPE
            || typeHint == ScriptRuntime.DoubleClass
            || typeHint == Double.TYPE) {
          hint = "number";
        } else {
          throw Context.reportRuntimeError(
              "Invalid JavaScript value of type " + typeHint.toString());
        }
        args[0] = hint;
      }
      Object v = ScriptableObject.getProperty(this, methodName);
      if (!(v instanceof Function)) continue;
      Function fun = (Function) v;
      Context cx = RhinoScriptEngine.enterContext();
      try {
        v = fun.call(cx, fun.getParentScope(), this, args);
      } finally {
        Context.exit();
      }
      if (v != null) {
        if (!(v instanceof Scriptable)) {
          return v;
        }
        if (typeHint == ScriptRuntime.ScriptableClass || typeHint == ScriptRuntime.FunctionClass) {
          return v;
        }
        if (tryToString && v instanceof Wrapper) {
          // Let a wrapped java.lang.String pass for a primitive
          // string.
          Object u = ((Wrapper) v).unwrap();
          if (u instanceof String) return u;
        }
      }
    }
    // fall through to error
    String arg = (typeHint == null) ? "undefined" : typeHint.getName();
    throw Context.reportRuntimeError("Cannot find default value for object " + arg);
  }
 @Override
 public int hashCode() {
   int result = engine.hashCode();
   result = 31 * result + compiledScript.hashCode();
   return result;
 }
 /**
  * {@inheritDoc}
  *
  * @param scriptContext The script context in which to evaluate the script. Cannot be null.
  */
 @Override
 public Object eval(final ScriptContext scriptContext) throws ScriptException {
   return engine.evalCompiled(compiledScript, scriptContext);
 }