1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
Optional chaining operators allow accessing nested object properties
in a secure manner, without the need to check the entire reference
chain for validity.
1. The `?.` operator can be used to lookup a named property in a
left-hand side expression without having to check whether the lhs
value is a proper object.
-- Expect stdout --
true
true
-- End --
-- Testcase --
{%
obj = { foo: 1 };
print(obj.bar?.baz == null, "\n"); // obj.bar is null
print(obj.foo?.bar == null, "\n"); // obj.foo is not an object
%}
-- End --
2. The `?.[…]` operator complements the `?.` one and applies the
same semantics to computed property accesses.
-- Expect stdout --
true
true
true
true
-- End --
-- Testcase --
{%
obj = { foo: 1 };
arr = [ 1, 2 ];
print(obj["bar"]?.["baz"] == null, "\n"); // obj.bar is null
print(obj["foo"]?.["bar"] == null, "\n"); // obj.foo is not an object
print(arr[0]?.["foo"] == null, "\n"); // arr[0] is not an object
print(foo?.[1] == null, "\n"); // foo is not an array
%}
-- End --
3. The `?.(…)` function call operator yields `null` when the left-hand
side value is not a callable function value.
-- Expect stdout --
true
true
-- End --
-- Testcase --
{%
foo = 1;
print(foo?.(1, 2, 3) == null, "\n"); // foo is not a function
print(bar?.("test") == null, "\n"); // bar is null
%}
-- End --
4. Optional chaining operators cannot be used on the left-hand side of
an assignment or increment/decrement expression.
-- Expect stderr --
Syntax error: Invalid left-hand side expression for assignment
In line 2, byte 13:
` obj?.foo = 1;`
Near here -----^
-- End --
-- Testcase --
{%
obj?.foo = 1;
%}
-- End --
-- Expect stderr --
Syntax error: Invalid increment/decrement operand
In line 2, byte 7:
` obj?.foo++;`
^-- Near here
-- End --
-- Testcase --
{%
obj?.foo++;
%}
-- End --
|