-
Notifications
You must be signed in to change notification settings - Fork 2
/
EmacsModule.hpp
51 lines (42 loc) · 1.77 KB
/
EmacsModule.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#pragma once
#include "emacs-module.h"
#include <string>
#include <map>
#include <tuple>
#include <stdexcept>
namespace detail {
template<typename T>
T extractArg(emacs_env *env, emacs_value v);
template<> std::string extractArg<std::string>(emacs_env *env, emacs_value v);
template<> int extractArg<int>(emacs_env *env, emacs_value v);
template <typename...ARGS, std::size_t... I>
auto extractArgsImpl(emacs_env *env, emacs_value* args, std::index_sequence<I...>) {
return std::make_tuple(extractArg<ARGS>(env, args[I])...);
}
template <typename...ARGS>
auto extractArgs(emacs_env *env, ptrdiff_t nargs, emacs_value* args) {
using indices = std::make_index_sequence<sizeof...(ARGS)>;
return extractArgsImpl<std::decay_t<ARGS>...>(env, args, indices{});
}
}
emacs_value sym(emacs_env *env, const std::string& name);
emacs_value reportError(emacs_env *env, const std::exception& e);
void provide(emacs_env *env, const char *feature);
template <class... ARGS>
void bindFunction(emacs_env *env, emacs_value f(emacs_env*, ARGS...), const char* name) {
auto numArgs = sizeof...(ARGS);
auto trampoline = [] (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void *data) noexcept {
auto func = reinterpret_cast<decltype(f)>(data);
auto argsTuple = detail::extractArgs<ARGS...>(env, nargs, args);
try {
return std::apply(func, std::tuple_cat(std::make_tuple(env), argsTuple));
} catch (std::exception& e) {
return reportError(env, e);
}
};
emacs_value Sfun = env->make_function(env, numArgs, numArgs, trampoline, name, reinterpret_cast<void*>(f));
emacs_value Qfset = sym(env, "fset");
emacs_value Qsym = env->intern(env, name);
emacs_value args[] = {Qsym, Sfun};
env->funcall(env, Qfset, 2, args);
}