Skip to content

Commit d4cedc0

Browse files
Added Symbol.toPrimitive to Date and Symbol prototypes.
1 parent 56dae7f commit d4cedc0

File tree

9 files changed

+305
-34
lines changed

9 files changed

+305
-34
lines changed

src/njs_date.c

Lines changed: 67 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,65 @@ 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;
1391+
1392+
if (njs_slow_path(!njs_is_date(&args[0]))) {
1393+
njs_type_error(vm, "cannot convert %s to date",
1394+
njs_type_string(args[0].type));
1395+
1396+
return NJS_ERROR;
1397+
}
1398+
1399+
if (njs_slow_path(nargs <= 1)) {
1400+
goto error;
1401+
}
1402+
1403+
if (njs_slow_path(!njs_is_string(&args[1]))) {
1404+
ret = njs_value_to_string(vm, &args[1], &args[1]);
1405+
if (njs_slow_path(ret != NJS_OK)) {
1406+
return ret;
1407+
}
1408+
}
1409+
1410+
ret = njs_atom_atomize_key(vm, &args[1]);
1411+
if (njs_slow_path(ret != NJS_OK)) {
1412+
return ret;
1413+
}
1414+
1415+
switch (args[1].atom_id) {
1416+
case NJS_ATOM_STRING_number:
1417+
hint = NJS_HINT_NUMBER;
1418+
break;
1419+
1420+
case NJS_ATOM_STRING_string:
1421+
case NJS_ATOM_STRING_default:
1422+
hint = NJS_HINT_STRING;
1423+
break;
1424+
1425+
default:
1426+
error:
1427+
njs_type_error(vm, "invalid hint");
1428+
return NJS_ERROR;
1429+
1430+
}
1431+
1432+
ret = njs_value_to_primitive(vm, &args[0], &args[0],
1433+
hint | NJS_HINT_FORCE_ORDINARY);
1434+
if (njs_slow_path(ret != NJS_OK)) {
1435+
return ret;
1436+
}
1437+
1438+
njs_value_assign(retval, &args[0]);
1439+
1440+
return NJS_OK;
1441+
}
1442+
1443+
13841444
static njs_int_t
13851445
njs_date_prototype_set_fields(njs_vm_t *vm, njs_value_t *args,
13861446
njs_uint_t nargs, njs_index_t magic, njs_value_t *retval)
@@ -1643,6 +1703,12 @@ static const njs_object_prop_init_t njs_date_prototype_properties[] =
16431703
NJS_DECLARE_PROP_NATIVE(STRING_setUTCFullYear,
16441704
njs_date_prototype_set_fields, 3,
16451705
njs_date_magic2(NJS_DATE_YR, 3, 0)),
1706+
1707+
/* NJS_DECLARE_PROP_NATIVE, but not writable */
1708+
NJS_DECLARE_PROP_VALUE(SYMBOL_toPrimitive,
1709+
njs_native_function2(njs_date_prototype_to_primitive,
1710+
1, 0),
1711+
NJS_OBJECT_PROP_VALUE_C),
16461712
};
16471713

16481714

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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,12 @@ 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, but not writable */
314+
NJS_DECLARE_PROP_VALUE(SYMBOL_toPrimitive,
315+
njs_native_function2(njs_symbol_prototype_value_of,
316+
1, 0),
317+
NJS_OBJECT_PROP_VALUE_C),
318+
313319
NJS_DECLARE_PROP_NATIVE(STRING_toString,
314320
njs_symbol_prototype_to_string, 0, 0),
315321

src/njs_value.c

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,27 @@ 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+
5354
if (njs_is_primitive(value)) {
5455
*dst = *value;
5556
return NJS_OK;
@@ -58,42 +59,86 @@ njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value,
5859
tries = 0;
5960
fhq.proto = &njs_object_hash_proto;
6061

62+
if (!njs_is_object(value)) {
63+
goto error;
64+
}
65+
66+
force_ordinary = hint & NJS_HINT_FORCE_ORDINARY;
67+
hint &= ~NJS_HINT_FORCE_ORDINARY;
68+
69+
if (force_ordinary) {
70+
goto ordinary;
71+
}
72+
73+
fhq.key_hash = NJS_ATOM_SYMBOL_toPrimitive;
74+
75+
ret = njs_object_property(vm, njs_object(value), &fhq, &method);
76+
if (njs_slow_path(ret == NJS_ERROR)) {
77+
return ret;
78+
}
79+
80+
if (njs_is_function(&method)) {
81+
arguments[0] = *value;
82+
83+
njs_atom_to_value(vm, &arguments[1], atom_by_hint[hint]);
84+
85+
ret = njs_function_apply(vm, njs_function(&method), arguments, 2,
86+
&retval);
87+
if (njs_slow_path(ret != NJS_OK)) {
88+
return ret;
89+
}
90+
91+
if (njs_is_primitive(&retval)) {
92+
goto done;
93+
}
94+
95+
goto error;
96+
}
97+
98+
ordinary:
99+
100+
if (hint != NJS_HINT_STRING) {
101+
hint = NJS_HINT_NUMBER;
102+
}
103+
61104
for ( ;; ) {
62105
ret = NJS_ERROR;
63106

64-
if (njs_is_object(value) && tries < 2) {
107+
if (tries < 2) {
65108
hint ^= tries++;
66109

67110
fhq.key_hash = atoms[hint];
68111

69112
ret = njs_object_property(vm, njs_object(value), &fhq, &method);
70-
71113
if (njs_slow_path(ret == NJS_ERROR)) {
72114
return ret;
73115
}
74116

75117
if (njs_is_function(&method)) {
76118
ret = njs_function_apply(vm, njs_function(&method), value, 1,
77119
&retval);
78-
79120
if (njs_slow_path(ret != NJS_OK)) {
80121
return ret;
81122
}
82123

83124
if (njs_is_primitive(&retval)) {
84-
break;
125+
goto done;
85126
}
86127
}
87128

88129
/* Try the second method. */
89130
continue;
90-
}
131+
}
132+
133+
error:
91134

92135
njs_type_error(vm, "Cannot convert object to primitive value");
93136

94-
return ret;
137+
return NJS_ERROR;
95138
}
96139

140+
done:
141+
97142
*dst = retval;
98143

99144
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
}

src/njs_vmcode.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, njs_value_t *rval,
8888
int32_t i32;
8989
uint32_t u32;
9090
njs_str_t string;
91-
njs_uint_t hint;
9291
njs_bool_t valid, lambda_call;
9392
njs_value_t *retval, *value1, *value2;
9493
njs_value_t *src, *s1, *s2, dst;
@@ -461,7 +460,8 @@ NEXT_LBL;
461460
njs_vmcode_operand(vm, vmcode->operand2, value1);
462461

463462
if (njs_slow_path(!njs_is_primitive(value1))) {
464-
ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
463+
ret = njs_value_to_primitive(vm, &primitive1, value1,
464+
NJS_HINT_NUMBER);
465465
if (ret != NJS_OK) {
466466
goto error;
467467
}
@@ -470,7 +470,8 @@ NEXT_LBL;
470470
}
471471

472472
if (njs_slow_path(!njs_is_primitive(value2))) {
473-
ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
473+
ret = njs_value_to_primitive(vm, &primitive2, value2,
474+
NJS_HINT_NUMBER);
474475
if (ret != NJS_OK) {
475476
goto error;
476477
}
@@ -500,7 +501,8 @@ NEXT_LBL;
500501
njs_vmcode_operand(vm, vmcode->operand2, value1);
501502

502503
if (njs_slow_path(!njs_is_primitive(value1))) {
503-
ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
504+
ret = njs_value_to_primitive(vm, &primitive1, value1,
505+
NJS_HINT_NUMBER);
504506
if (ret != NJS_OK) {
505507
goto error;
506508
}
@@ -509,7 +511,8 @@ NEXT_LBL;
509511
}
510512

511513
if (njs_slow_path(!njs_is_primitive(value2))) {
512-
ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
514+
ret = njs_value_to_primitive(vm, &primitive2, value2,
515+
NJS_HINT_NUMBER);
513516
if (ret != NJS_OK) {
514517
goto error;
515518
}
@@ -539,7 +542,8 @@ NEXT_LBL;
539542
njs_vmcode_operand(vm, vmcode->operand2, value1);
540543

541544
if (njs_slow_path(!njs_is_primitive(value1))) {
542-
ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
545+
ret = njs_value_to_primitive(vm, &primitive1, value1,
546+
NJS_HINT_NUMBER);
543547
if (ret != NJS_OK) {
544548
goto error;
545549
}
@@ -548,7 +552,8 @@ NEXT_LBL;
548552
}
549553

550554
if (njs_slow_path(!njs_is_primitive(value2))) {
551-
ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
555+
ret = njs_value_to_primitive(vm, &primitive2, value2,
556+
NJS_HINT_NUMBER);
552557
if (ret != NJS_OK) {
553558
goto error;
554559
}
@@ -578,7 +583,8 @@ NEXT_LBL;
578583
njs_vmcode_operand(vm, vmcode->operand2, value1);
579584

580585
if (njs_slow_path(!njs_is_primitive(value1))) {
581-
ret = njs_value_to_primitive(vm, &primitive1, value1, 0);
586+
ret = njs_value_to_primitive(vm, &primitive1, value1,
587+
NJS_HINT_NUMBER);
582588
if (ret != NJS_OK) {
583589
goto error;
584590
}
@@ -587,7 +593,8 @@ NEXT_LBL;
587593
}
588594

589595
if (njs_slow_path(!njs_is_primitive(value2))) {
590-
ret = njs_value_to_primitive(vm, &primitive2, value2, 0);
596+
ret = njs_value_to_primitive(vm, &primitive2, value2,
597+
NJS_HINT_NUMBER);
591598
if (ret != NJS_OK) {
592599
goto error;
593600
}
@@ -617,8 +624,8 @@ NEXT_LBL;
617624
njs_vmcode_operand(vm, vmcode->operand2, value1);
618625

619626
if (njs_slow_path(!njs_is_primitive(value1))) {
620-
hint = njs_is_date(value1);
621-
ret = njs_value_to_primitive(vm, &primitive1, value1, hint);
627+
ret = njs_value_to_primitive(vm, &primitive1, value1,
628+
NJS_HINT_NONE);
622629
if (ret != NJS_OK) {
623630
goto error;
624631
}
@@ -627,8 +634,8 @@ NEXT_LBL;
627634
}
628635

629636
if (njs_slow_path(!njs_is_primitive(value2))) {
630-
hint = njs_is_date(value2);
631-
ret = njs_value_to_primitive(vm, &primitive2, value2, hint);
637+
ret = njs_value_to_primitive(vm, &primitive2, value2,
638+
NJS_HINT_NONE);
632639
if (ret != NJS_OK) {
633640
goto error;
634641
}
@@ -2478,7 +2485,7 @@ njs_values_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
24782485

24792486
/* "hv" is an object and "lv" is either a string or a symbol or a numeric. */
24802487

2481-
ret = njs_value_to_primitive(vm, &primitive, hv, 0);
2488+
ret = njs_value_to_primitive(vm, &primitive, hv, NJS_HINT_NONE);
24822489
if (ret != NJS_OK) {
24832490
return ret;
24842491
}

0 commit comments

Comments
 (0)