template<> int scoreArg<QByteArray>(SEXP arg, const SmokeType &type) { if (TYPEOF(arg) == STRSXP) return type.isPtr() ? 1 : 2; else if (TYPEOF(arg) == RAWSXP) return type.isPtr() ? 2 : 3; else return scoreArg_basetype(arg, type); }
void marshal_from_sexp<SmokeClassWrapper>(MethodCall *m) { SEXP v = m->sexp(); SmokeType type = m->type(); SmokeObject *o = NULL /*, *coerced = NULL */; /* Not clear if we want to (partially) support this complicated C++ feature if (v != R_NilValue) { o = SmokeObject::fromSexp(v); if (!o->instanceOf(type.className())) { // attempt implicit conversion coerced = o->convertImplicitly(type); if (coerced) o = coerced; else error("Failed to coerce an instance of type '%s' to '%s'", o->className(), type.className()); } } */ o = from_sexp<SmokeObject *>(v, type); void *ptr = o ? o->castPtr(type.className(), m->returning() && !type.fitsStack()) : NULL; setItemValue(m, ptr); /* m->marshal(); if (coerced) delete coerced; */ return; }
bool matches_arg(Smoke *smoke, Smoke::Index meth, Smoke::Index argidx, const char *argtype) { Smoke::Index *arg = smoke->argumentList + smoke->methods[meth].args + argidx; SmokeType type = SmokeType(smoke, *arg); if (type.name() && qstrcmp(type.name(), argtype) == 0) { return true; } return false; }
template<> int scoreArg<unsigned char>(SEXP arg, const SmokeType &type) { int score = 0; // we consider ptr as array of bytes, and Qt will not copy, but R might free if (!type.isPtr()) { switch(TYPEOF(arg)) { case RAWSXP: score = 3; break; case INTSXP: case REALSXP: score = 1; break; default: break; } } return score; }
Marshall::HandlerFn getMarshallFn(const SmokeType &type) { if(type.elem()) return marshall_basetype; if(!type.name()) return marshall_void; TypeHandler *h = type_handlers[type.name()]; if(h == 0 && type.isConst() && strlen(type.name()) > strlen("const ")) { h = type_handlers[type.name() + strlen("const ")]; } if(h != 0) { return h->fn; } return marshall_unknown; }
Marshall::HandlerFn Marshall::getMarshallFn(const SmokeType &type) { if (type.element() != 0) { return marshall_basetype; } if (type.name() == 0) { return marshall_void; } TypeHandler * handler = TypeHandlers[type.name()]; if (handler == 0 && type.isConst() && qstrlen(type.name()) > qstrlen("const ")) { handler = TypeHandlers[type.name() + qstrlen("const ")]; } if (handler != 0) { return handler->fn; } return marshall_unknown; }
bool SmokeObject::instanceOf(const SmokeType &type) const { Smoke *smoke = this->smoke(); return smoke->isDerivedFrom(smoke, classId(), type.smoke(), type.classId()); }
SEXP SmokeObject::sexpFromPtr(void *ptr, const SmokeType &type, bool allocated, bool copy) { return sexpFromPtr(ptr, type.smoke(), type.classId(), allocated, copy); }
template<> int scoreArg<QString>(SEXP arg, const SmokeType &type) { if (TYPEOF(arg) == STRSXP) return type.isPtr() ? 1 : 3; else return 0; }
int scoreArg_unknown(SEXP /*arg*/, const SmokeType &type) { error("unable to score argument of type '%s'", type.name()); return 0; }
/* C++ compilers select overloaded methods by ranking each argument in terms of its implicit conversions. There are three different types of implicit conversions: standard, user and ellipsis. We only consider the former, as the others probably are not relevant for Qt. Within standard conversions, there are three ranks: exact, promotion and conversion. We assign these scores 3, 2 and 1, respectively, while 0 indicates no conversion and -1 indicates an error (e.g. unsupported type). The method with better or same ranks for all of its parameters is selected. If there is a tie for the best method, there is an error (in our code). */ int scoreArg_basetype(SEXP arg, const SmokeType &type) { int score = 0; SEXP value = arg; int rtype = TYPEOF(value); unsigned short elem = type.elem(); switch(rtype) { // try the simple cases first case RAWSXP: switch(elem) { case Smoke::t_uchar: score = 3; break; case Smoke::t_short: case Smoke::t_ushort: score = 2; break; case Smoke::t_int: case Smoke::t_uint: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 1; break; default: break; } break; case INTSXP: switch(elem) { case Smoke::t_enum: if (inherits(value, "QtEnum")) score = 2; else score = 1; break; case Smoke::t_int: score = 3; break; case Smoke::t_uint: if (inherits(value, "QtEnum")) { score = 3; // favor QFlags over enums break; } case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 2; break; case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: score = 1; break; default: break; } break; case REALSXP: switch(elem) { case Smoke::t_double: score = 3; break; case Smoke::t_float: case Smoke::t_uint: // to distinguish int/uint score = 2; break; case Smoke::t_int: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: case Smoke::t_enum: score = 1; break; default: break; } break; case STRSXP: if (elem == Smoke::t_char && strlen(CHAR(asChar(value))) == 1) score = 2; break; case ENVSXP: if (elem == Smoke::t_class) { SmokeObject *o = SmokeObject::fromSexp(value); if (o) { const char *smokeClass = type.className(); if (o->className() == smokeClass) score = 3; else if (o->instanceOf(smokeClass)) score = 2; /* Not clear if we want to support this C++ feature else { Method *m = Class::fromSmokeType(type)->findImplicitConverter(o); if (m) { score = 1; delete m; } } */ } } break; case NILSXP: if (type.isPtr()) score = 1; break; default: break; } return score; }
/* Clean-up when: (1) Smoke returns something that doesn't fit in StackItem OR (2) Passing arguments to Smoke OR (3) Returning something to Smoke that fits in StackItem. */ inline bool cleanup() const { SmokeType t = type(); return (_mode == RToSmoke && (_cur || (!_cur && t.fitsStack()))) || (!t.fitsStack() && !_cur && _mode == SmokeToR); }