@@ -30,26 +30,28 @@ const njs_value_t njs_value_zero = njs_value(NJS_NUMBER, 0, 0.0);
3030const njs_value_t njs_value_nan = njs_value (NJS_NUMBER , 0 , NAN );
3131const njs_value_t njs_value_invalid = njs_value (NJS_INVALID , 0 , 0.0 );
3232
33- /*
34- * A hint value is 0 for numbers and 1 for strings. The value chooses
35- * method calls order specified by ECMAScript 5.1: "valueOf", "toString"
36- * for numbers and "toString", "valueOf" for strings.
37- */
3833
3934njs_int_t
4035njs_value_to_primitive (njs_vm_t * vm , njs_value_t * dst , njs_value_t * value ,
4136 njs_uint_t hint )
4237{
4338 njs_int_t ret ;
44- njs_uint_t tries ;
45- njs_value_t method , retval ;
39+ njs_uint_t tries , force_ordinary ;
40+ njs_value_t method , retval , arguments [ 2 ] ;
4641 njs_flathsh_query_t fhq ;
4742
4843 static const uint32_t atoms [] = {
4944 NJS_ATOM_STRING_valueOf ,
5045 NJS_ATOM_STRING_toString ,
5146 };
5247
48+ static const njs_uint_t atom_by_hint [] = {
49+ NJS_ATOM_STRING_number ,
50+ NJS_ATOM_STRING_string ,
51+ NJS_ATOM_STRING_default ,
52+ };
53+
54+
5355 if (njs_is_primitive (value )) {
5456 * dst = * value ;
5557 return NJS_OK ;
@@ -58,42 +60,87 @@ njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value,
5860 tries = 0 ;
5961 fhq .proto = & njs_object_hash_proto ;
6062
63+ ret = NJS_ERROR ;
64+
65+ if (!njs_is_object (value )) {
66+ goto ret_error ;
67+ }
68+
69+ force_ordinary = hint & NJS_HINT_FORCE_ORDINARY ;
70+ hint &= ~NJS_HINT_FORCE_ORDINARY ;
71+
72+ if (force_ordinary ) {
73+ goto ordinary ;
74+ }
75+
76+ fhq .key_hash = NJS_ATOM_SYMBOL_toPrimitive ;
77+
78+ ret = njs_object_property (vm , njs_object (value ), & fhq , & method );
79+ if (njs_slow_path (ret == NJS_ERROR )) {
80+ return ret ;
81+ }
82+
83+ if (njs_is_function (& method )) {
84+ arguments [0 ] = * value ;
85+
86+ njs_atom_to_value (vm , & arguments [1 ], atom_by_hint [hint ]);
87+
88+ ret = njs_function_apply (vm , njs_function (& method ), arguments , 2 ,
89+ & retval );
90+ if (njs_slow_path (ret != NJS_OK )) {
91+ return ret ;
92+ }
93+
94+ if (njs_is_primitive (& retval )) {
95+ goto ret_val ;
96+ }
97+ goto ret_error ;
98+ }
99+
100+ ordinary :
101+
102+ if (hint != NJS_HINT_STRING ) {
103+ hint = NJS_HINT_NUMBER ;
104+ }
105+
61106 for ( ;; ) {
62107 ret = NJS_ERROR ;
63108
64- if (njs_is_object ( value ) && tries < 2 ) {
109+ if (tries < 2 ) {
65110 hint ^= tries ++ ;
66111
67112 fhq .key_hash = atoms [hint ];
68113
69114 ret = njs_object_property (vm , njs_object (value ), & fhq , & method );
70-
71115 if (njs_slow_path (ret == NJS_ERROR )) {
72116 return ret ;
73117 }
74118
75119 if (njs_is_function (& method )) {
76120 ret = njs_function_apply (vm , njs_function (& method ), value , 1 ,
77121 & retval );
78-
79122 if (njs_slow_path (ret != NJS_OK )) {
80123 return ret ;
81124 }
82125
83126 if (njs_is_primitive (& retval )) {
84- break ;
127+ goto ret_val ;
85128 }
86129 }
87130
88131 /* Try the second method. */
89132 continue ;
90- }
133+ }
134+
135+ ret_error :
91136
92137 njs_type_error (vm , "Cannot convert object to primitive value" );
93138
94139 return ret ;
95140 }
96141
142+ ret_val :
143+
97144 * dst = retval ;
98145
99146 return NJS_OK ;
0 commit comments