Io Programming/Binding Io to C++

      The following code example shows a simple class bound to Io. The binding was tested to work, but it may not be fully correct.

      The IoBindingTest class only stores a number, with the usual setter and getter accessors. Also, two instances of the class can be compared to each other. The class has the regular constructor, as well as a copy constructor, and a constructor that takes a number. The copy constructor is used in the binding when creating a clone.

      // begin test class
      
      class IoBindingTest;
      
      class IoBindingTest
      {
      public:
       IoBindingTest() : num(0) {};
       IoBindingTest(int n) : num(n) {};
       IoBindingTest(IoBindingTest* ptr) : num(ptr->num) {};
       ~IoBindingTest() {};
       
       int GetNum(void) { return num; };
       void SetNum(int n) { num = n; };
       
       bool CompareWith(IoBindingTest* obj) { return num == obj->num; };
      
      private:
       int num;
      };
      
      // end test class
      

      The binding class creates a bunch of static class functions, which can be accessed from C code, such as Io's VM, for using the test class' similarly named instance methods. Also, the binding class has methods specific to the Io VM (proto, tag, rawClone, mark, free), and a final function to add the binding to the VM at runtime.

      #include "IoVM.h"
      
      class IoBindingTest_io
      {
      public:
       static IoObject* GetNum(IoObject *self, IoObject *locals, IoMessage *m);
       static IoObject* SetNum(IoObject *self, IoObject *locals, IoMessage *m);
      
       static IoObject* CompareWith(IoObject *self, IoObject *locals, IoMessage *m);
      
       static IoObject* proto(IoState* state);
       
       static IoTag* tag(IoState* state, const char* name);
      
       static IoObject* rawClone(IoObject* self);
       static IoObject* mark(IoObject* self);
       static IoObject* free(IoObject* self);
       
       static void addBinding(IoState* state);
      
      };
      
      IoTag *IoBindingTest_io::tag(IoState* state, const char* name)
      {
       IoTag* tag = IoTag_newWithName_(name);
       tag->state = state;
       tag->cloneFunc = (TagCloneFunc*) rawClone;
       tag->markFunc = (TagMarkFunc*) mark;
       tag->freeFunc = (TagFreeFunc*) free;
      
       return tag;
      }
      

      The proto function is used for creating the initial prototype in the Io VM.

      IoObject *IoBindingTest_io::proto(IoState* state)
      {
       IoMethodTable methods[] = {
       {"GetNum", GetNum},
       {"SetNum", SetNum},
       {"CompareWith", CompareWith},
       {NULL, NULL}
       };
       IoObject* self = IoObject_new(state);
       self->tag = tag(state, "IoBindingTest");
       self->data = 0;
       IoObject_addMethodTable_(self, methods);
       return self;
      }
      

      The addBinding function is used to put the prototype of our object into the Io VM at runtime.

      void IoBindingTest_io::addBinding(IoState* state)
      {
       IoObject* self = proto(state);
       IoState_registerProtoWithFunc_(state, self, (IoStateProtoFunc*)proto);
       IoObject_setSlot_to_(state->lobby, IOSYMBOL("IoBindingTest"), self);
      }
      
      IoObject *IoBindingTest_io::rawClone(IoObject *self)
      {
       IoObject *clone = IoObject_rawClonePrimitive(self);
       if (self->data)
        clone->data = new IoBindingTest(reinterpret_cast<IoBindingTest*>(self->data));
       else
        clone->data = new IoBindingTest;
       return clone;
      }
      

      The mark function is used by the garbage collector. If the C++ object has references to other objects in the Io VM, they must also be marked.

      IoObject *IoBindingTest_io::mark(IoObject *self)
      {
       return self;
      }
      

      free is pretty self-explanatory, this is where the C++ object should be freed/deleted, if appropriate.

      IoObject *IoBindingTest_io::free(IoObject *self)
      {
       if (self->data)
       {
        IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
        delete obj;
        self->data = NULL;
       }
       return self;
      }
      

      The following three functions are the actual bindings of the instance methods, so that they can be called from a script.

      IoObject* IoBindingTest_io::GetNum(IoObject *self, IoObject *locals, IoMessage *m)
      {
       IOASSERT(self->data, "No C++ object");
       IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
      
       return IoNumber_newWithDouble_(self->state, obj->GetNum());
      
      };
      
      IoObject* IoBindingTest_io::SetNum(IoObject *self, IoObject *locals, IoMessage *m)
      {
       IOASSERT(self->data, "No C++ object");
       IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
      
       IOASSERT(IoMessage_argCount(m) == 1, "Wrong number of arguments");
       
       IoObject *arg1 = IoMessage_locals_numberArgAt_(m, locals, 0);
      
       obj->SetNum(IoNumber_asInt(arg1));
      
       return self;
      
      };
      
      IoObject* IoBindingTest_io::CompareWith(IoObject *self, IoObject *locals, IoMessage *m)
      {
       IOASSERT(self->data, "No C++ object");
       IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
      
       IOASSERT(IoMessage_argCount(m) == 1, "Wrong number of arguments");
       
       IoObject *arg1 = IoMessage_locals_valueArgAt_(m, locals, 0);
      
       // make sure the object is tagged  
       IOASSERT(arg1->tag, "No tag in arg");
      
       // check the tag to make sure it is the right object class
       IOASSERT(strcmp(arg1->tag->name, "IoBindingTest") == 0, "arg not IoBindingTest object");
      
       // check for the actual existence of the C++ object
       IOASSERT(arg1->data, "No C++ object in arg");
      
       IoBindingTest* arg1obj = reinterpret_cast<IoBindingTest*>(arg1->data);
      
       // bool is simulated by returning self or nil
       if (obj->CompareWith(arg1obj))
        return self;
       else
        return IONIL(self);
      };
      
      Last modified on 17 December 2008, at 02:51