mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 07:48:37 -04:00
interrogate: Reimplement subscript assignment "operator"
This redoes the handling of `obj[n] = item` to occur in InterrogateBuilder instead so that it doesn't prevent the same remap from being used as getitem. This fixes the non-const variant of InstanceList[n].
This commit is contained in:
parent
5ef1b44455
commit
18e8918138
@ -419,6 +419,17 @@ get_call_str(const string &container, const vector_string &pexprs) const {
|
||||
call << ')';
|
||||
}
|
||||
|
||||
} else if (_type == T_item_assignment_operator) {
|
||||
call << "(";
|
||||
_parameters[0]._remap->pass_parameter(call, container);
|
||||
call << ")[";
|
||||
|
||||
size_t pn = _first_true_parameter;
|
||||
_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
|
||||
call << "] = ";
|
||||
++pn;
|
||||
_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
|
||||
|
||||
} else {
|
||||
const char *separator = "";
|
||||
|
||||
@ -468,11 +479,6 @@ get_call_str(const string &container, const vector_string &pexprs) const {
|
||||
size_t pn = _first_true_parameter;
|
||||
size_t num_parameters = pexprs.size();
|
||||
|
||||
if (_type == T_item_assignment_operator) {
|
||||
// The last parameter is the value to set.
|
||||
--num_parameters;
|
||||
}
|
||||
|
||||
for (pn = _first_true_parameter;
|
||||
pn < num_parameters; ++pn) {
|
||||
nassertd(pn < _parameters.size()) break;
|
||||
@ -481,11 +487,6 @@ get_call_str(const string &container, const vector_string &pexprs) const {
|
||||
separator = ", ";
|
||||
}
|
||||
call << ")";
|
||||
|
||||
if (_type == T_item_assignment_operator) {
|
||||
call << " = ";
|
||||
_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
|
||||
}
|
||||
}
|
||||
|
||||
return call.str();
|
||||
@ -568,6 +569,9 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
|
||||
} else if ((ifunc._flags & InterrogateFunction::F_setter) != 0) {
|
||||
_type = T_setter;
|
||||
|
||||
} else if ((ifunc._flags & InterrogateFunction::F_item_assignment) != 0) {
|
||||
_type = T_item_assignment_operator;
|
||||
}
|
||||
|
||||
if ((_cppfunc->_storage_class & CPPInstance::SC_blocking) != 0) {
|
||||
@ -623,14 +627,6 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
fname == "operator <<=" ||
|
||||
fname == "operator >>=") {
|
||||
_type = T_assignment_method;
|
||||
|
||||
} else if (fname == "operator []" && !_const_method && rtype != nullptr) {
|
||||
// Check if this is an item-assignment operator.
|
||||
CPPReferenceType *reftype = rtype->as_reference_type();
|
||||
if (reftype != nullptr && reftype->_pointing_at->as_const_type() == nullptr) {
|
||||
// It returns a mutable reference.
|
||||
_type = T_item_assignment_operator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -707,37 +703,6 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
}
|
||||
}
|
||||
|
||||
} else if (_type == T_item_assignment_operator) {
|
||||
// An item-assignment method isn't really a thing in C++, but it is in
|
||||
// scripting languages, so we use this to denote item-access operators
|
||||
// that return a non-const reference.
|
||||
|
||||
if (_cpptype == nullptr) {
|
||||
nout << "Method " << *_cppfunc << " has no struct type\n";
|
||||
return false;
|
||||
} else {
|
||||
// Synthesize a const reference parameter for the assignment.
|
||||
CPPType *bare_type = TypeManager::unwrap_reference(rtype);
|
||||
CPPType *const_type = CPPType::new_type(new CPPConstType(bare_type));
|
||||
CPPType *ref_type = CPPType::new_type(new CPPReferenceType(const_type));
|
||||
|
||||
Parameter param;
|
||||
param._has_name = true;
|
||||
param._name = "assign_val";
|
||||
param._remap = interface_maker->remap_parameter(_cpptype, ref_type);
|
||||
|
||||
if (param._remap == nullptr || !param._remap->is_valid()) {
|
||||
nout << "Invalid remap for assignment type of method " << *_cppfunc << "\n";
|
||||
return false;
|
||||
}
|
||||
_parameters.push_back(param);
|
||||
|
||||
// Pretend we don't return anything at all.
|
||||
CPPType *void_type = TypeManager::get_void_type();
|
||||
_return_type = interface_maker->remap_parameter(_cpptype, void_type);
|
||||
_void_return = true;
|
||||
}
|
||||
|
||||
} else if (fname == "operator <=>") {
|
||||
// This returns an opaque object that we must leave unchanged.
|
||||
_return_type = new ParameterRemapUnchanged(rtype);
|
||||
|
@ -74,6 +74,7 @@ RenameSet methodRenameDictionary[] = {
|
||||
{ "operator =" , "assign", 0 },
|
||||
{ "operator ()" , "__call__", 0 },
|
||||
{ "operator []" , "__getitem__", 0 },
|
||||
{ "operator [] =" , "__setitem__", 0 },
|
||||
{ "operator ++unary", "increment", 0 },
|
||||
{ "operator ++" , "increment", 0 },
|
||||
{ "operator --unary", "decrement", 0 },
|
||||
|
@ -3012,6 +3012,38 @@ define_method(CPPInstance *function, InterrogateType &itype,
|
||||
index) == itype._methods.end()) {
|
||||
itype._methods.push_back(index);
|
||||
}
|
||||
|
||||
// For an operator [] returning a non-const reference, we synthesize an
|
||||
// "item-assignment" operator, which does not exist in C++ but does in
|
||||
// scripting languages. This allows `obj[n] = ...`
|
||||
if (ftype->_return_type != nullptr &&
|
||||
ftype->_return_type->is_reference() &&
|
||||
!ftype->_return_type->remove_reference()->is_const() &&
|
||||
(ftype->_flags & CPPFunctionType::F_const_method) == 0 &&
|
||||
function->get_simple_name() == "operator []") {
|
||||
|
||||
// Make up a CPPFunctionType with extra parameter.
|
||||
CPPType *assign_type = TypeManager::wrap_const_reference(ftype->_return_type->remove_reference());
|
||||
CPPParameterList *params = new CPPParameterList(*(ftype->_parameters));
|
||||
CPPInstance *param1 = new CPPInstance(assign_type, "assign_val");
|
||||
params->_parameters.push_back(param1);
|
||||
CPPType *void_type = TypeManager::get_void_type();
|
||||
CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
|
||||
|
||||
// Now make up an instance for the function.
|
||||
CPPInstance *function = new CPPInstance(ftype, "operator [] =");
|
||||
function->_ident->_native_scope = scope;
|
||||
|
||||
FunctionIndex index = get_function(function, "",
|
||||
struct_type, scope,
|
||||
InterrogateFunction::F_item_assignment);
|
||||
if (index != 0) {
|
||||
if (find(itype._methods.begin(), itype._methods.end(),
|
||||
index) == itype._methods.end()) {
|
||||
itype._methods.push_back(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ private:
|
||||
F_setter = 0x0020,
|
||||
F_unary_op = 0x0040,
|
||||
F_operator_typecast = 0x0080,
|
||||
F_item_assignment = 0x0100,
|
||||
};
|
||||
|
||||
int _flags;
|
||||
|
Loading…
x
Reference in New Issue
Block a user