* Reject empty computed member expressions before returning slices[0] from parse_member_expression_arguments().
* Treat empty computed member expressions with Jinja2 undefined semantics
Treat empty computed member expressions like `a[]` as undefined instead of
raising a parser error, to match Jinja2 behavior.
- return a noop expression for empty computed member arguments
- return undefined when a computed member key evaluates to undefined
- add Jinja tests covering `a[]|default('fallback')` and `a[] is undefined`
* Handle undefined computed member properties
Move undefined-property handling to the common member access path, and add a test covering `a[undefined] is undefined`.
* Use default undefined value in member access
Initialize val and then return it when property is undefined.
Co-authored-by: Sigbjørn Skjæret <redacted>
* empty statement parses to blank_expression instead of noop_statement
---------
Co-authored-by: Sigbjørn Skjæret <redacted>
statement_ptr step = slices.size() > 2 ? std::move(slices[2]) : nullptr;
return mk_stmt<slice_expression>(start_pos, std::move(start), std::move(stop), std::move(step));
}
+ if (slices.empty()) {
+ return mk_stmt<blank_expression>(start_pos);
+ }
return std::move(slices[0]);
}
}
JJ_DEBUG("Member expression on object type %s, property type %s", object->type().c_str(), property->type().c_str());
- ensure_key_type_allowed(property);
-
value val = mk_val<value_undefined>("object_property");
+ if (property->is_undefined()) {
+ JJ_DEBUG("%s", "Member expression property is undefined, returning undefined");
+ return val;
+ }
+
+ ensure_key_type_allowed(property);
+
if (is_val<value_undefined>(object)) {
JJ_DEBUG("%s", "Accessing property on undefined object, returning undefined");
return val;
// Expressions
+// Represents an omitted expression in a computed member, e.g. `a[]`.
+struct blank_expression : public expression {
+ std::string type() const override { return "BlankExpression"; }
+ value execute_impl(context &) override {
+ return mk_val<value_undefined>();
+ }
+};
+
struct member_expression : public expression {
statement_ptr object;
statement_ptr property;
"Bob"
);
+ test_template(t, "empty computed member defaults to undefined",
+ "{{ a[]|default('fallback') }}",
+ {{"a", {{"name", "Bob"}}}},
+ "fallback"
+ );
+
+ test_template(t, "empty computed member is undefined",
+ "{{ a[] is undefined }}",
+ {{"a", {{"name", "Bob"}}}},
+ "True"
+ );
+
+ test_template(t, "undefined computed member is undefined",
+ "{{ a[undefined] is undefined }}",
+ {{"a", {{"name", "Bob"}}}},
+ "True"
+ );
+
test_template(t, "array access",
"{{ items[1] }}",
{{"items", json::array({"a", "b", "c"})}},