Перевод вызова Gravity (языка сценариев) в вызов родной функции C - PullRequest
0 голосов
/ 29 января 2019

В настоящее время я пытаюсь реализовать более чистый способ вызова собственных функций C из языка сценариев Gravity .

На данный момент наиболее простым примером будет этот:

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

Если бы с помощью шаблонов C ++ (98) или магии препроцессора C был бы способ генерировать функции-оболочки?:

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

Технически это то, чего я хочу достичь - но с помощью таких методов, как препроцессор или C ++.По причинам кросс-платформенной совместимости я бы хотел придерживаться C ++ 98 (поскольку MSVC не совсем хорош в современных функциях).

1 Ответ

0 голосов
/ 31 января 2019

Это довольно утомительно без вариационных шаблонов, но вы должны иметь возможность привести небольшое количество аргументов:

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

Как обычно, void возвращаемые типы будут проблемой;Вы должны повторять каждую перегрузку подсчета аргументов для R из void.

Можно было бы использовать вычет, чтобы избежать повторения подписи при использовании wrap, но затемвы получаете меньше функций и дополнительных объектов замыкания, чтобы различать их (которые вы, вероятно, можете использовать через аргумент data).

...