pub(crate) fn ordinary_to_primitive(
        &self,
        context: &mut Context,
        hint: PreferredType,
    ) -> JsResult<JsValue> {
        // 1. Assert: Type(O) is Object.
        //      Already is JsObject by type.
        // 2. Assert: Type(hint) is String and its value is either "string" or "number".
        debug_assert!(hint == PreferredType::String || hint == PreferredType::Number);

        // Diverge from the spec here to make sure we aren't going to overflow the stack by converting
        // a recursive structure
        // We can follow v8 & SpiderMonkey's lead and return a default value for the hint in this situation
        // (see https://repl.it/repls/IvoryCircularCertification#index.js)
        let recursion_limiter = RecursionLimiter::new(self);
        if recursion_limiter.live {
            // we're in a recursive object, bail
            return Ok(match hint {
                PreferredType::Number => JsValue::new(0),
                PreferredType::String => JsValue::new(""),
                PreferredType::Default => unreachable!("checked type hint in step 2"),
            });
        }

        // 3. If hint is "string", then
        //    a. Let methodNames be « "toString", "valueOf" ».
        // 4. Else,
        //    a. Let methodNames be « "valueOf", "toString" ».
        let method_names = if hint == PreferredType::String {
            ["toString", "valueOf"]
        } else {
            ["valueOf", "toString"]
        };

        // 5. For each name in methodNames in List order, do
        let this = JsValue::new(self.clone());
        for name in &method_names {
            // a. Let method be ? Get(O, name).
            let method: JsValue = this.get_field(*name, context)?;
            // b. If IsCallable(method) is true, then
            if method.is_function() {
                // i. Let result be ? Call(method, O).
                let result = context.call(&method, &this, &[])?;
                // ii. If Type(result) is not Object, return result.
                if !result.is_object() {
                    return Ok(result);
                }
            }
        }

        // 6. Throw a TypeError exception.
        context.throw_type_error("cannot convert object to primitive value")
    }
/// Converts an object to a primitive.
///
/// Diverges from the spec to prevent a stack overflow when the object is recursive.
/// For example,
/// ```javascript
/// let a = [1];
/// a[1] = a;
/// console.log(a.toString()); // We print "1,"
/// ```
/// The spec doesn't mention what to do in this situation, but a naive implementation
/// would overflow the stack recursively calling `toString()`. We follow v8 and SpiderMonkey
/// instead by returning a default value for the given `hint` -- either `0.` or `""`.
/// Example in v8: <https://repl.it/repls/IvoryCircularCertification#index.js>
///
/// More information:
///  - [ECMAScript][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinarytoprimitive
Converts an object to a primitive.
Diverges from the spec to prevent a stack overflow when the object is recursive.




Converts an object to a primitive . Diverges from the spec to prevent a stack overflow when the object is recursive .
pub(crate) fn ordinary_to_primitive(
        &self,
        context: &mut Context,
        hint: PreferredType,
    ) -> JsResult<JsValue> {
        // 1. Assert: Type(O) is Object.
        //      Already is JsObject by type.
        // 2. Assert: Type(hint) is String and its value is either "string" or "number".
        debug_assert!(hint == PreferredType::String || hint == PreferredType::Number);
        // Diverge from the spec here to make sure we aren't going to overflow the stack by converting
        // a recursive structure
        // We can follow v8 & SpiderMonkey's lead and return a default value for the hint in this situation
        // (see https://repl.it/repls/IvoryCircularCertification#index.js)
        let recursion_limiter = RecursionLimiter::new(self);
        if recursion_limiter.live {
            // we're in a recursive object, bail
            return Ok(match hint {
                PreferredType::Number => JsValue::new(0),
                PreferredType::String => JsValue::new(""),
                PreferredType::Default => unreachable!("checked type hint in step 2"),
            });
        }
        // 3. If hint is "string", then
        //    a. Let methodNames be « "toString", "valueOf" ».
        // 4. Else,
        //    a. Let methodNames be « "valueOf", "toString" ».
        let method_names = if hint == PreferredType::String {
            ["toString", "valueOf"]
        } else {
            ["valueOf", "toString"]
        };
        // 5. For each name in methodNames in List order, do
        let this = JsValue::new(self.clone());
        for name in &method_names {
            // a. Let method be ? Get(O, name).
            let method: JsValue = this.get_field(*name, context)?;
            // b. If IsCallable(method) is true, then
            if method.is_function() {
                // i. Let result be ? Call(method, O).
                let result = context.call(&method, &this, &[])?;
                // ii. If Type(result) is not Object, return result.
                if !result.is_object() {
                    return Ok(result);
                }
            }
        }
        // 6. Throw a TypeError exception.
        context.throw_type_error("cannot convert object to primitive value")
    }
pub ( crate ) fn ordinary_to_primitive ( & self , context : & mut Context , hint : PreferredType , ) -> JsResult < JsValue > { // 1. Assert: Type(O) is Object. //      Already is JsObject by type. // 2. Assert: Type(hint) is String and its value is either "string" or "number". debug_assert ! ( hint PreferredType String hint PreferredType Number ) ; // Diverge from the spec here to make sure we aren't going to overflow the stack by converting // a recursive structure // We can follow v8 & SpiderMonkey's lead and return a default value for the hint in this situation // (see https://repl.it/repls/IvoryCircularCertification#index.js) let recursion_limiter = RecursionLimiter :: new ( self ) ; if recursion_limiter . live { // we're in a recursive object, bail return Ok ( match hint { PreferredType :: Number => JsValue :: new ( 0 ) , PreferredType :: String => JsValue :: new ( " " ) , PreferredType :: Default => unreachable ! ( " " ) , } ) ; } // 3. If hint is "string", then //    a. Let methodNames be « "toString", "valueOf" ». // 4. Else, //    a. Let methodNames be « "valueOf", "toString" ». let method_names = if hint == PreferredType :: String { [ " " , " " ] } else { [ " " , " " ] } ; // 5. For each name in methodNames in List order, do let this = JsValue :: new ( self . clone ( ) ) ; for name in & method_names { // a. Let method be ? Get(O, name). let method : JsValue = this . get_field ( * name , context ) ? ; // b. If IsCallable(method) is true, then if method . is_function ( ) { // i. Let result be ? Call(method, O). let result = context . call ( & method , & this , & [ ] ) ? ; // ii. If Type(result) is not Object, return result. if ! result . is_object ( ) { return Ok ( result ) ; } } } // 6. Throw a TypeError exception. context . throw_type_error ( " " ) }
Converts an object to a primitive.
Converts an object to a primitive .
&self
context
&mut Context
hint
PreferredType
&self
context
&mut Context
hint
PreferredType