Esempio n. 1
0
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;
}
Esempio n. 2
0
QByteArray
MethodCall::argKey(SEXP arg) const
{
  const char * className = CHAR(asChar(getAttrib(arg, R_ClassSymbol)));
  const char *r = "";
  if (arg == R_NilValue)
    r = "u";
  else if (TYPEOF(arg) == INTSXP) {
    if (inherits(arg, "QtEnum"))
      r = className;
    else r = "i";
  } else if (TYPEOF(arg) == REALSXP)
    r = "n";
  else if (TYPEOF(arg) == STRSXP)
    r = "s";
  else if(TYPEOF(arg) == LGLSXP)
    r = "B";
  else if (TYPEOF(arg) == EXTPTRSXP) {
    SmokeObject *o = SmokeObject::fromSexp(arg);
    if (o == 0 || o->smoke() == 0) {
      r = "a";
    } else {
      r = o->smoke()->classes[o->classId()].className;
    }
  } else {
    r = "U";
  }
  return QByteArray(r);
}
Esempio n. 3
0
SEXP
SmokeObject::sexpFromPtr(void *ptr, const Class *klass,
                         bool allocated, bool copy)
{
  SmokeObject *so = fromPtr(ptr, klass, allocated, copy);
  if (!so)
    return R_NilValue;
  else return so->sexp();
}
Esempio n. 4
0
void *_unwrapSmoke(SEXP x, const char *type) {
  void *ans = NULL;
  if (!isNull(x)) {
    SmokeObject *so = SmokeObject::fromSexp(x);
    if (so)
      ans = so->castPtr(type);
  }
  return ans;
}
Esempio n. 5
0
SEXP qt_qdataFrameModel(SEXP rparent, SEXP useRoles, SEXP editable) {
    static Class *dataFrameModelClass =
        new NameOnlyClass("DataFrameModel", Class::fromName("QAbstractTableModel"));
    SmokeObject *so =
        SmokeObject::fromPtr(new DataFrameModel(unwrapSmoke(rparent, QObject),
                             useRoles, editable),
                             Class::fromName("QAbstractTableModel"), true);
    so->cast(dataFrameModelClass);
    return so->sexp();
}
Esempio n. 6
0
extern "C" SEXP qt_qmetaInvoke(SEXP x, SEXP s_id, SEXP s_args) {
  SmokeObject *so = SmokeObject::fromSexp(x);
  int id = from_sexp<int>(s_id);
  QObject * qobj = reinterpret_cast<QObject *>(so->castPtr("QObject"));
  MocMethod method(so->smoke(), qobj->metaObject(), id);
  SEXP ret = method.invoke(x, s_args);
  if (method.lastError() > Method::NoError)
    error("Meta method invocation failed for: '%s::%s'", so->klass()->name(),
          method.name());
  return ret;
}
Esempio n. 7
0
/* We catch all qt_metacall invocations */
extern "C" SEXP qt_qmetacall(SEXP x, SEXP s_call, SEXP s_id, SEXP s_args)
{
  SmokeObject *so = SmokeObject::fromSexp(x);
  QMetaObject::Call call =
    enum_from_sexp<QMetaObject::Call>(s_call, SmokeType());
  int id = from_sexp<int>(s_id);
  void **args = reinterpret_cast<void **>(from_sexp<void *>(s_args));
  
  // Assume the target slot is a C++ one
  Smoke::StackItem i[4];
  i[1].s_enum = call;
  i[2].s_int = id;
  i[3].s_voidp = args;
  so->invokeMethod("qt_metacall$$?", i);
  int ret = i[0].s_int;
  if (ret < 0) {
    return ScalarInteger(ret);
  }

  if (call != QMetaObject::InvokeMetaMethod)
    return ScalarInteger(id);

  QObject * qobj = reinterpret_cast<QObject *>(so->castPtr("QObject"));
  // get obj metaobject with a virtual call
  const QMetaObject *metaobject = qobj->metaObject();
  
  // get method count
  int count = metaobject->methodCount();
  
  QMetaMethod method = metaobject->method(id);
  if (method.methodType() == QMetaMethod::Signal) {
    // FIXME: this override of 'activate' is obsolete
    metaobject->activate(qobj, id, (void**) args);
    return ScalarInteger(id - count);
  }
  DynamicBinding binding(MocMethod(so->smoke(), metaobject, id));
  QVector<SmokeType> stackTypes = binding.types();
  MocStack mocStack = MocStack(args, stackTypes.size());
  SmokeStack smokeStack = mocStack.toSmoke(stackTypes);
  binding.invoke(so, smokeStack.items());
  mocStack.returnFromSmoke(smokeStack, stackTypes[0]);
  if (binding.lastError() == Method::NoError)
    warning("Slot invocation failed for %s::%s", so->klass()->name(),
            binding.name());
  
  return ScalarInteger(id - count);
}
Esempio n. 8
0
Method*
MocClass::findMethod(const MethodCall& call) const {
  Method *method = _delegate->findMethod(call);
  if (method)
    return(method);
  SmokeObject *o = call.target();
  /* only QObjects have meta methods */
  if (o && o->ptr() && o->instanceOf("QObject") && o->klass() == this) {
    /* unwrap the call */
    QObject * qobject = reinterpret_cast<QObject *>(o->castPtr("QObject"));
    const QMetaObject * meta = qobject->metaObject();
    /* get the method id */
    int id = findMethodId(o->smoke(), meta, call.method()->name(), call.args());
    if (id >= 0)
      method = new MocMethod(o->smoke(), meta, id);
  }
  return method;
}
Esempio n. 9
0
SmokeObject * SmokeObject::fromPtr(void *ptr, const Class *klass,
                                   bool allocated, bool copy)
{
  if (!klass)
    error("Attempt to create SmokeObject with NULL class");
  if (!ptr)
    error("Attempt to create SmokeObject with NULL pointer");
  SmokeObject *so = instances[ptr];
  if (!so) {
    so = new SmokeObject(ptr, klass, allocated);
#ifdef MEM_DEBUG
    qDebug("%p: created for %p (%s)", so, ptr, klass->name());
#endif
    // record this ASAP, resolveClassId() needs it for virtual callbacks
    if (allocated) // do not record unallocated; not informed when deleted
      instances[so->ptr()] = so;
#ifdef MEM_DEBUG
    else qDebug("%p: unallocated, not registering pointer", so);
#endif
    so->cast(Class::fromSmokeId(so->smoke(), so->module()->resolveClassId(so)));
    /* it seems that all multiple inheritance in Qt goes through
       QObject or QEvent, so we can catch offset pointers at run-time */
    // FIXME: what happens with other libraries? take QtRuby approach?
#ifdef MEM_DEBUG
    if (allocated && so->klass() != klass)
      qDebug("%p: class switch %s::%s -> %s::%s", so,
             klass->smokeBase()->smoke()->moduleName(),
             klass->name(), so->klass()->smokeBase()->smoke()->moduleName(),
             so->klass()->name());
#endif    
    if (so->ptr() != ptr) { // must be multiple inheritance, recache
      SmokeObject *tmp_so = instances[so->ptr()];
#ifdef MEM_DEBUG
      qDebug("%p: multiple inheritance detected, switch to %p", so, so->ptr());
#endif
      if (tmp_so) {
#ifdef MEM_DEBUG
      qDebug("%p: replaced with existing %p", so, tmp_so);
#endif
        delete so;
        so = tmp_so;
        copy = false; // don't think we every want to copy here
      } else instances[so->ptr()] = so;
      instances.remove(ptr);
    }
    if (copy) { // copy the data
      void *tmp_ptr = so->ptr();
      so->_ptr = so->clonePtr(); 
      instances[so->ptr()] = so; // update the instances hash after cloning
      instances.remove(tmp_ptr);
#ifdef MEM_DEBUG
      qDebug("%p: copied to %p", so, so->ptr());
#endif
      so->_allocated = true;
    }
  }
  return so;
}
Esempio n. 10
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;
}
Esempio n. 11
0
QVariant qvariant_from_sexp(SEXP rvalue, int index) {
  QVariant variant;
  if (index == -1) {
    /* If a particular element is not selected, then non-lists of
       length one are considered scalars. Otherwise, collections.
       Except for raw vectors, which are naturally QByteArrays.
    */
    if (TYPEOF(rvalue) == RAWSXP)
      return QVariant(from_sexp<QByteArray>(rvalue));
    else if (TYPEOF(rvalue) == VECSXP || length(rvalue) > 1) {
      SEXP rlist = coerceVector(rvalue, VECSXP);
      if (getAttrib(rvalue, R_NamesSymbol) != R_NilValue)
        variant = asQVariantOfType(rlist, QMetaType::QVariantMap);
      else variant = asQVariantOfType(rlist, QMetaType::QVariantList);
      return variant;
    }
    index = 0;
  }
  switch(TYPEOF(rvalue)) {
  case RAWSXP:
    variant = qVariantFromValue(RAW(rvalue)[index]);
    break;
  case LGLSXP:
    // Rprintf("Logical\n");
    // FIXME: by converting to 'bool' all NA become TRUE
    variant = QVariant((bool)LOGICAL(rvalue)[index]);
    break;
  case REALSXP:
    // Rprintf("Real\n");
    variant = QVariant(REAL(rvalue)[index]);
    break;
  case INTSXP:
    // Rprintf("Integer\n");
    {
      SEXP levels;
      if ((levels = getAttrib(rvalue, R_LevelsSymbol)) != R_NilValue) {
        int level = INTEGER(rvalue)[index];
        SEXP level_str = NA_STRING;
        /*Rprintf("getting level: %d\n", level);*/
        if (level != NA_INTEGER)
          level_str = STRING_ELT(levels, level - 1);
        variant = QVariant(sexp2qstring(level_str));
      } else variant = QVariant(INTEGER(rvalue)[index]);
      break;
    }
  case STRSXP:
    // Rprintf("String\n");
    variant = QVariant(sexp2qstring(STRING_ELT(rvalue, index)));
    break;
  case EXTPTRSXP:
    // Rprintf("External pointer\n");
    variant = qVariantFromValue(unwrapPointer(rvalue, void));
    break;
  case VECSXP:
    variant = from_sexp<QVariant>(VECTOR_ELT(rvalue, index));
    break;
  case ENVSXP: {
    SmokeObject *so = SmokeObject::fromSexp(rvalue);
    if (so->instanceOf("QWidget"))
      variant =
        qVariantFromValue(reinterpret_cast<QWidget *>(so->castPtr("QWidget")));
    else if (so->instanceOf("QObject"))
      variant =
        qVariantFromValue(reinterpret_cast<QObject *>(so->castPtr("QObject")));
    else {
      QMetaType::Type type = (QMetaType::Type) QMetaType::type(so->className());
      if (type)
        variant = asQVariantOfType(rvalue, type, false);
      else variant = qVariantFromValue(so->ptr());
    }
  }
    break;
  case NILSXP: // invalid QVariant
    break;
  default:
    error("Converting to QVariant: unhandled R type");
  }
  return variant;
}
Esempio n. 12
0
SEXP qt_qcast(SEXP x, SEXP klass) {
  SmokeObject *obj = SmokeObject::fromSexp(x);
  obj->cast(Class::fromSexp(klass));
  return obj->sexp();
}