跳转到内容

Io 编程/将 Io 绑定到 C++

来自维基教科书,开放世界中的开放书籍

以下代码示例展示了一个简单的绑定到 Io 的类。绑定已通过测试,但可能不完全正确。

IoBindingTest 类只存储一个数字,并提供通常的 setter 和 getter 访问器。此外,可以比较两个类的实例。该类具有常规的构造函数,以及一个复制构造函数和一个接受数字的构造函数。在绑定中创建克隆时使用复制构造函数。

// 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

绑定类创建了一堆静态类函数,这些函数可以从 C 代码(如 Io 的 VM)访问,用于使用测试类的同名实例方法。此外,绑定类还具有特定于 Io VM 的方法(proto、tag、rawClone、mark、free),以及一个在运行时将绑定添加到 VM 的最终函数。

#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;
}

proto 函数用于在 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;
}

addBinding 函数用于在运行时将我们对象的原型放入 Io VM 中。

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;
}

mark 函数由垃圾收集器使用。如果 C++ 对象引用了 Io VM 中的其他对象,则也必须标记这些对象。

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

free 顾名思义,这是在适当的情况下释放/删除 C++ 对象的地方。

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

以下三个函数是实例方法的实际绑定,因此可以从脚本中调用它们。

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);
};
华夏公益教科书