+ def _operator(self, op, left_val, right_expr, expr, local_vars, allow_recursion):
+ if op in ('||', '&&'):
+ if (op == '&&') ^ _ternary(left_val):
+ return left_val # short circuiting
+ elif op == '?':
+ right_expr = _ternary(left_val, *self._separate(right_expr, ':', 1))
+
+ right_val = self.interpret_expression(right_expr, local_vars, allow_recursion)
+ if not _OPERATORS.get(op):
+ return right_val
+
+ try:
+ return _OPERATORS[op](left_val, right_val)
+ except Exception as e:
+ raise self.Exception(f'Failed to evaluate {left_val!r} {op} {right_val!r}', expr, cause=e)
+
+ def _index(self, obj, idx):
+ if idx == 'length':
+ return len(obj)
+ try:
+ return obj[int(idx)] if isinstance(obj, list) else obj[idx]
+ except Exception as e:
+ raise self.Exception(f'Cannot get index {idx}', repr(obj), cause=e)
+
+ def _dump(self, obj, namespace):
+ try:
+ return json.dumps(obj)
+ except TypeError:
+ return self._named_object(namespace, obj)
+
+ @Debugger.wrap_interpreter