summaryrefslogtreecommitdiffhomepage
path: root/tests/custom/00_syntax/23_optional_chaining
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-09-25 19:34:14 +0200
committerJo-Philipp Wich <jo@mein.io>2021-10-11 09:39:12 +0200
commit4ee06d8138a107908a9fb45220fea32055b3c48a (patch)
tree2f0bd421931b2dd2daf504719beb63cc2885d23a /tests/custom/00_syntax/23_optional_chaining
parente43b751aab997c5e74a0712f7569d90bd3d6b429 (diff)
syntax: introduce optional chaining operators
Introduce new operators `?.`, `?.[…]` and `?.(…)` to simplify looking up deeply nested property chain in a secure manner. The `?.` operator behaves like the `.` property access operator but yields `null` if the left hand side is `null` or not an object. Like `?.`, the `?.[…]` operator behaves like the `[…]` computed property access but yields `null` if the left hand side is `null` or neither an object or array. Finally the `?.(…)` operator behaves like the function call operator `(…)` but yields `null` if the left hand side is `null` or not a callable function. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'tests/custom/00_syntax/23_optional_chaining')
-rw-r--r--tests/custom/00_syntax/23_optional_chaining99
1 files changed, 99 insertions, 0 deletions
diff --git a/tests/custom/00_syntax/23_optional_chaining b/tests/custom/00_syntax/23_optional_chaining
new file mode 100644
index 0000000..8b89089
--- /dev/null
+++ b/tests/custom/00_syntax/23_optional_chaining
@@ -0,0 +1,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 --