diff --git a/examples/calendar/main.cpp b/examples/calendar/main.cpp
new file mode 100644
index 0000000..331682f
--- /dev/null
+++ b/examples/calendar/main.cpp
@@ -0,0 +1,143 @@
+/* Copyright 2020, Michele Santullo
+ * This file is part of wrenpp.
+ *
+ * Wrenpp is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wrenpp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wrenpp. If not, see .
+ */
+
+#include "wrenpp/def_configuration.hpp"
+#include "wrenpp/vm_fun.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ constexpr const char g_calendar_src[] =
+"foreign class Calendar {" R"script(
+ construct new() {}
+ foreign static today()
+ foreign add_appointment(desc)
+}
+)script";
+
+ constexpr const char g_test_script[] =
+R"script(import "calendar" for Calendar
+var cale = Calendar.new()
+System.print("Today is %(Calendar.today())")
+cale.add_appointment("go get a haircut")
+)script";
+
+ auto today_unique_str() {
+ std::time_t now = std::time(nullptr);
+ constexpr const std::size_t buff_sz = 1024;
+ auto mem(std::make_unique(buff_sz));
+ const std::size_t sz = std::strftime(mem.get(), buff_sz, "%A %-e %B %Y", std::localtime(&now));
+ if (not sz)
+ std::strcpy(mem.get(), "n/a");
+ return mem;
+ }
+
+ class Calendar {
+ public:
+ Calendar() {
+ //std::cout << "Calendar initialized\n";
+ }
+
+ ~Calendar() {
+ try {
+ //std::cout << "Calendar destroyed\n";
+ }
+ catch (...) {
+ }
+ }
+
+ static void today (wren::VM& vm) {
+ vm.set_slot_string(0, today_unique_str().get());
+ }
+
+ void add_appointment (wren::VM& vm) {
+ m_appointments.push_back(wren::get(vm, 1));
+ }
+
+ void print_appointments() const {
+ std::cout << "Appointments for " << today_unique_str().get() << ":\n";
+ if (m_appointments.empty()) {
+ std::cout << "\t[none]\n";
+ }
+ else {
+ for (const auto& app : m_appointments) {
+ std::cout << '\t' << app << '\n';
+ }
+ }
+ }
+
+ private:
+ std::vector m_appointments;
+ };
+
+ class MyConf : public wren::DefConfiguration {
+ public:
+ char* load_module_fn(wren::VM* vm, const char* module_name) {
+ if (std::string_view{module_name} == "calendar") {
+ constexpr const std::size_t buff_sz = sizeof(g_calendar_src);
+ char* const buff = static_cast(MyConf::reallocate_fn(nullptr, buff_sz));
+ std::copy(g_calendar_src, g_calendar_src + buff_sz / sizeof(g_calendar_src[0]), buff);
+ return buff;
+ }
+ return nullptr;
+ }
+
+ wren::foreign_method_t foreign_method_fn(wren::VM* vm, const char* m, const char* c, bool is_static, const char* s) {
+ std::string_view module(m);
+ std::string_view class_name(c);
+ std::string_view signature(s);
+
+ if (module == "calendar" and class_name == "Calendar") {
+ if (is_static and signature == "today()")
+ return &Calendar::today;
+ else if (not is_static and signature == "add_appointment(_)")
+ return wren::make_method_bindable<&Calendar::add_appointment>();
+ }
+ return nullptr;
+ }
+
+ wren::foreign_class_t foreign_class_fn(wren::VM* vm, const char* m, const char* c) {
+ std::string_view module(m);
+ std::string_view class_name(c);
+
+ if (module == "calendar" and class_name == "Calendar") {
+ return wren::make_foreign_class();
+ }
+ else {
+ return {nullptr, nullptr};
+ }
+ }
+ };
+} //unnamed namespace
+
+int main() {
+ MyConf conf;
+ wren::VM vm(&conf, nullptr);
+ vm.interpret("main", g_test_script);
+
+ vm.ensure_slots(1);
+ wren::variable(vm, {"main", "cale"}, 0);
+ const auto cale = wren::foreign(vm, 0);
+ cale->print_appointments();
+
+ return 0;
+}
diff --git a/examples/calendar/meson.build b/examples/calendar/meson.build
new file mode 100644
index 0000000..f9b2f61
--- /dev/null
+++ b/examples/calendar/meson.build
@@ -0,0 +1,5 @@
+executable('calendar',
+ 'main.cpp',
+ dependencies: wrenpp_dep,
+ install: false,
+)
diff --git a/examples/meson.build b/examples/meson.build
index 1e27a26..46175a9 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,2 +1,3 @@
subdir('dieroll')
subdir('greet')
+subdir('calendar')
diff --git a/include/wrenpp/vm_fun.hpp b/include/wrenpp/vm_fun.hpp
index 432a77a..7df58d0 100644
--- a/include/wrenpp/vm_fun.hpp
+++ b/include/wrenpp/vm_fun.hpp
@@ -56,6 +56,12 @@ namespace wren {
template
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
+ template
+ foreign_class_t make_foreign_class();
+
+ template
+ foreign_method_t make_method_bindable();
+
void interpret (VM& vm, const std::string& module_name, const std::string& script);
void set (VM& vm, int slot_num, const char* value);
void set (VM& vm, int slot_num, double value);
@@ -69,6 +75,7 @@ namespace wren {
void set (VM& vm, int slot_num, int value);
std::string_view slot_string_view (VM& vm, int slot_num);
template T get (VM& vm, int slot_num);
+ template T* foreign (VM& vm, int slot_num);
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot);
void variable(VM& vm, const Handle& handle, int slot);
@@ -116,6 +123,16 @@ namespace wren {
vm.ensure_slots(sizeof...(Args));
(set_single_for_call(vm, Indices + 1, args), ...);
}
+
+ template struct MakeMethodBindable;
+ template struct MakeMethodBindable {
+ static foreign_method_t make() {
+ return [](VM& vm) {
+ T* obj = foreign(vm, 0);
+ (obj->*Method)(vm);
+ };
+ }
+ };
} //namespace detail
#if __cpp_concepts >= 201907
@@ -167,6 +184,12 @@ namespace wren {
vm.set_slot_double(slot_num, static_cast(value));
}
+ template
+ inline T* foreign (VM& vm, int slot_num) {
+ T* obj = static_cast(vm.slot_foreign(slot_num));
+ return obj;
+ }
+
template
inline R call (VM& vm, const Handle& object, const Handle& method, const Args&... args) {
detail::set_for_call(std::make_integer_sequence(), vm, args...);
@@ -205,4 +228,24 @@ namespace wren {
Handle obj_handle = vm.slot_handle(0);
return call(vm, obj_handle, method, args...);
}
+
+ template
+ inline foreign_class_t make_foreign_class() {
+ foreign_class_t ret;
+ ret.allocate = [](VM& vm) {
+ void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
+ new(mem) T;
+ };
+ ret.finalize = [](void* mem) {
+ const auto cale = static_cast(mem);
+ cale->~T();
+ };
+
+ return ret;
+ }
+
+ template
+ inline foreign_method_t make_method_bindable() {
+ return detail::MakeMethodBindable::make();
+ }
} //namespace wren