From 90d93d258393bf370e6587d1c3b2ea085777005a Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sun, 3 May 2020 01:54:00 +0200 Subject: [PATCH] Add calendar example and supporting functions --- examples/calendar/main.cpp | 143 ++++++++++++++++++++++++++++++++++ examples/calendar/meson.build | 5 ++ examples/meson.build | 1 + include/wrenpp/vm_fun.hpp | 43 ++++++++++ 4 files changed, 192 insertions(+) create mode 100644 examples/calendar/main.cpp create mode 100644 examples/calendar/meson.build 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