Skip to content

Commit bf585ab

Browse files
Making sure using of Symbol.toPrimitive property.
1 parent 8b08b3d commit bf585ab

File tree

10 files changed

+166
-33
lines changed

10 files changed

+166
-33
lines changed

src/njs_atom_defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ NJS_DEF_STRING(includes, "includes", 0, 0)
297297
NJS_DEF_STRING(index, "index", 0, 0)
298298
NJS_DEF_STRING(indexOf, "indexOf", 0, 0)
299299
NJS_DEF_STRING(input, "input", 0, 0)
300+
NJS_DEF_STRING(integer, "integer", 0, 0)
300301
NJS_DEF_STRING(is, "is", 0, 0)
301302
NJS_DEF_STRING(isArray, "isArray", 0, 0)
302303
NJS_DEF_STRING(isBuffer, "isBuffer", 0, 0)

src/njs_date.c

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ njs_date_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
411411
} else if (nargs == 2) {
412412
if (njs_is_object(&args[1])) {
413413
if (!njs_is_date(&args[1])) {
414-
ret = njs_value_to_primitive(vm, &args[1], &args[1], 0);
414+
ret = njs_value_to_primitive(vm, &args[1], &args[1],
415+
NJS_HINT_NONE);
415416
if (njs_slow_path(ret != NJS_OK)) {
416417
return ret;
417418
}
@@ -1381,6 +1382,69 @@ njs_date_prototype_set_time(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
13811382
}
13821383

13831384

1385+
static njs_int_t
1386+
njs_date_prototype_to_primitive(njs_vm_t *vm, njs_value_t *args,
1387+
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
1388+
{
1389+
njs_int_t ret;
1390+
njs_uint_t hint_num;
1391+
1392+
hint_num = 0;
1393+
1394+
if (njs_slow_path(!njs_is_date(&args[0]))) {
1395+
njs_type_error(vm, "cannot convert %s to date",
1396+
njs_type_string(args[0].type));
1397+
1398+
return NJS_ERROR;
1399+
}
1400+
1401+
if (nargs > 1) {
1402+
if (njs_slow_path(!njs_is_string(&args[1]))) {
1403+
ret = njs_value_to_string(vm, &args[1], &args[1]);
1404+
if (njs_slow_path(ret != NJS_OK)) {
1405+
return ret;
1406+
}
1407+
}
1408+
1409+
ret = njs_atom_atomize_key(vm, &args[1]);
1410+
if (ret != NJS_OK) {
1411+
return ret;
1412+
}
1413+
1414+
switch(args[1].atom_id) {
1415+
1416+
case NJS_ATOM_STRING_number:
1417+
hint_num = NJS_HINT_NUMBER;
1418+
break;
1419+
1420+
case NJS_ATOM_STRING_string:
1421+
case NJS_ATOM_STRING_default:
1422+
hint_num = NJS_HINT_STRING;
1423+
break;
1424+
1425+
default:
1426+
njs_type_error(vm, "invalid hint");
1427+
return NJS_ERROR;
1428+
1429+
}
1430+
1431+
} else {
1432+
njs_type_error(vm, "invalid hint");
1433+
return NJS_ERROR;
1434+
}
1435+
1436+
ret = njs_value_to_primitive(vm, &args[0], &args[0],
1437+
hint_num | NJS_HINT_FORCE_ORDINARY);
1438+
if (njs_slow_path(ret != NJS_OK)) {
1439+
return ret;
1440+
}
1441+
1442+
njs_value_assign(retval, &args[0]);
1443+
1444+
return NJS_OK;
1445+
}
1446+
1447+
13841448
static njs_int_t
13851449
njs_date_prototype_set_fields(njs_vm_t *vm, njs_value_t *args,
13861450
njs_uint_t nargs, njs_index_t magic, njs_value_t *retval)
@@ -1643,6 +1707,9 @@ static const njs_object_prop_init_t njs_date_prototype_properties[] =
16431707
NJS_DECLARE_PROP_NATIVE(STRING_setUTCFullYear,
16441708
njs_date_prototype_set_fields, 3,
16451709
njs_date_magic2(NJS_DATE_YR, 3, 0)),
1710+
1711+
NJS_DECLARE_PROP_NATIVE(SYMBOL_toPrimitive, njs_date_prototype_to_primitive,
1712+
1, 0),
16461713
};
16471714

16481715

src/njs_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ njs_value_to_key2(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value,
186186

187187
} else {
188188
if (convert) {
189-
ret = njs_value_to_primitive(vm, &primitive, value, 1);
189+
ret = njs_value_to_primitive(vm, &primitive, value,
190+
NJS_HINT_STRING);
190191

191192
} else {
192193
ret = njs_object_to_string(vm, value, &primitive);

src/njs_symbol.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ static const njs_object_prop_init_t njs_symbol_prototype_properties[] =
310310
NJS_DECLARE_PROP_NATIVE(STRING_valueOf, njs_symbol_prototype_value_of,
311311
0, 0),
312312

313+
NJS_DECLARE_PROP_NATIVE(SYMBOL_toPrimitive, njs_symbol_prototype_value_of,
314+
1, 0),
315+
313316
NJS_DECLARE_PROP_NATIVE(STRING_toString,
314317
njs_symbol_prototype_to_string, 0, 0),
315318

src/njs_value.c

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,28 @@ const njs_value_t njs_value_zero = njs_value(NJS_NUMBER, 0, 0.0);
3030
const njs_value_t njs_value_nan = njs_value(NJS_NUMBER, 0, NAN);
3131
const 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

3934
njs_int_t
4035
njs_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;

src/njs_value.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,11 @@ njs_set_object_value(njs_value_t *value, njs_object_value_t *object_value)
940940
#define njs_set_invalid(value) \
941941
(value)->type = NJS_INVALID
942942

943+
#define NJS_HINT_NUMBER 0
944+
#define NJS_HINT_STRING 1
945+
#define NJS_HINT_NONE 2
946+
#define NJS_HINT_FORCE_ORDINARY (1 << 3)
947+
943948
njs_int_t njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst,
944949
njs_value_t *value, njs_uint_t hint);
945950
njs_array_t *njs_value_enumerate(njs_vm_t *vm, njs_value_t *value,

src/njs_value_conversion.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ njs_value_to_number(njs_vm_t *vm, njs_value_t *value, double *dst)
1515
njs_value_t primitive;
1616

1717
if (njs_slow_path(!njs_is_primitive(value))) {
18-
ret = njs_value_to_primitive(vm, &primitive, value, 0);
18+
ret = njs_value_to_primitive(vm, &primitive, value, NJS_HINT_NUMBER);
1919
if (njs_slow_path(ret != NJS_OK)) {
2020
return NJS_ERROR;
2121
}
@@ -172,7 +172,8 @@ njs_value_to_chain(njs_vm_t *vm, njs_chb_t *chain, njs_value_t *value)
172172
value = njs_object_value(value);
173173

174174
} else {
175-
ret = njs_value_to_primitive(vm, &primitive, value, 1);
175+
ret = njs_value_to_primitive(vm, &primitive, value,
176+
NJS_HINT_STRING);
176177
if (njs_slow_path(ret != NJS_OK)) {
177178
return ret;
178179
}

src/njs_vm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,8 @@ njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
15601560
value = njs_object_value(value);
15611561

15621562
} else {
1563-
ret = njs_value_to_primitive(vm, &primitive, value, 1);
1563+
ret = njs_value_to_primitive(vm, &primitive, value,
1564+
NJS_HINT_STRING);
15641565
if (njs_slow_path(ret != NJS_OK)) {
15651566
return ret;
15661567
}

0 commit comments

Comments
 (0)