简体   繁体   English

将Gravity(脚本语言)调用转换为本机C函数调用

[英]Translating a Gravity (a scripting language) call to a native C function call

I am currently looking into implementing a cleaner way to call native C functions from the Gravity scripting language. 我目前正在寻求实现一种更简洁的方法来从Gravity脚本语言调用本机C函数。

So far, the most simplistic example would be this one: 到目前为止,最简单的例子是:

int add(int lhs, int rhs) {
  return lhs + rhs;
}

static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  int lhs, rhs, rt;

  // Unwrap
  lhs = VALUE_AS_INT(args[1]);
  rhs = VALUE_AS_INT(args[2]);

  // Perform call, capture return
  rt = add(lhs, rhs);

  // Forward the return
  gravity_vm_setslot(vm, VALUE_FROM_INT(rt), retIndex);
}

By using C++ (98) templating or C preprocessor magic, would there be a way to generate wrapper functions? 通过使用C ++(98)模板或C预处理器魔术,有没有办法生成包装函数?

A very, very crunched example of the above wrapper function, would be this one: 上面这个包装函数的一个非常非常紧凑的例子是:

static void gravity_wrap_add(
  gravity_vm* vm,
  gravity_value_t* args, uint32_t nargs, 
  uint32_t retIndex, void* data
) {
  gravity_vm_setslot(vm, 
   VALUE_FROM_INT(
     add(VALUE_AS_INT(args[1]), VALUE_AS_INT(args[2]))
   ), 
  retIndex);
}

This version is technically what I want to achieve - but through methods like the preprocessor or C++ templating. 这个版本在技术上是我想要实现的 - 但是通过预处理器或C ++模板等方法。 For cross-platform compatibility reasons, I'd like to stick with C++98 (since MSVC isn't exactly good on modern features). 出于跨平台兼容性的原因,我想坚持使用C ++ 98(因为MSVC在现代功能上并不完美)。

It's pretty tedious without variadic templates, but you should be able to do a small number of arguments: 没有可变参数模板这很乏味,但你应该能够做少量的参数:

namespace gravity {
  template<class T> struct value {};
  // for brevity and deduction:
  template<class T> T get(const gravity_value_t &v)
  {return value<T>::get(v);}
  template<class T> gravity_value_t put(const T &t)
  {return value<T>::put(t);}
  template<> struct value<int> {
    int get(const gravity_value_t &v)
    {return VALUE_AS_INT(v);}
    gravity_value_t put(int i)
    {return VALUE_FROM_INT(i);}
  };
  // more specializations…

  template<class R,R f()>
  void wrap(gravity_vm* vm,
            gravity_value_t* args, uint32_t nargs, 
            uint32_t retIndex, void* data) {
    assert(nargs==0);
    gravity_vm_setslot(vm,put(f()),retIndex);
  }
  template<class R,class A,R f(A)>
  void wrap(gravity_vm* vm,
            gravity_value_t* args, uint32_t nargs, 
            uint32_t retIndex, void* data) {
    assert(nargs==1);
    gravity_vm_setslot(vm,put(f(get<A>(args[0]))),retIndex);
  }
  // more overloads with more arguments…

  /*gravity_register*/(wrap<int,int,int,add>);
}

As usual, void return types will be a pain; 像往常一样, void返回类型将是一种痛苦; you have to repeat each argument-count overload for R of void . 你必须为R of void重复每个参数计数重载。

It would be possible to use deduction to avoid repeating the signature when using wrap , but then you get fewer functions and extra closure objects to distinguish them (which you can presumably use via the data argument). 可以使用演绎来避免在使用wrap时重复签名,但是你会得到更少的函数和额外的闭包对象来区分它们(你可以通过data参数使用它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM