Compare commits

..

4 commits

68 changed files with 878 additions and 3284 deletions

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
tags
compile_commands.json
subprojects/wren/

3
.gitmodules vendored
View file

@ -0,0 +1,3 @@
[submodule "subprojects/wren/wren"]
path = subprojects/wren/wren
url = https://github.com/wren-lang/wren.git

143
README.md
View file

@ -5,8 +5,6 @@ library. It aims to package all the features accessible through the C API in a
modern C++ interface that is easy to use, while keeping the overhead to a
minimum.
* [Current state](#current-state)
* [Philosophy](#philosophy)
* [Building](#building)
* [Wrenpp](#wrenpp)
* [Wren only](#wren-only)
@ -15,29 +13,6 @@ minimum.
* [C++](#c)
* [Header files](#header-files)
* [Initialisation](#initialisation)
* [Foreign functions](#foreign-functions)
* [Implementation](#implementation)
## Current state ##
The library is functional and provides access to most of the features of Wren.
Some are better tested than others. There are no known memory leaks. Please
keep in mind this is an early version and more testing and work will be needed.
## Philosophy ##
The overall principle behind this wrapper is to be feature rich while also
being lightweight and allowing fine-grained control for users who need it.
By design, wrenpp hides the Wren C API entirely, but all functions (considered
"low level" relative to this wrapper) are still accessible through the `VM`
class. If the function you need is not available there it's probably just
missing and adding it should be a trivial task.
Wrenpp provides you with convenience functions in `vm_fun.hpp` that are built
on top of the `VM` class and make basic use of Wren simpler. You're still free
to "mix & match" higher level functions with lower level ones, and you can
decide to not use portions of the wrapper entirely.
## Building ##
@ -64,12 +39,6 @@ The build scripts understand the following options (double check in
[random](http://wren.io/modules/random/) support
5. `wren_with_meta` set to true to compile Wren with
[meta](http://wren.io/modules/meta/) support
6. `wrenpp_with_name_guessing` enable class name guessing in c++ code. It
currently affects only example code and header files, not the library
itself. It controls the `WRENPP_WITH_NAME_GUESSING` preprocessor symbol.
When it's defined, you will have access to better error reporting and extra
functions, such as a `make_wren_object()` overload that doesn't require you
to specify a string class name.
Note that some example projects require random support in Wren, without which
they will crash. If you want to run examples or you are getting "Address
@ -117,19 +86,6 @@ executable('my_project',
)
```
And the matching wrenpp.wrap file for your project (remember to update the
revision SHA and the dependency name):
```
[wrap-git]
url = https://alarmpi.no-ip.org/gitan/King_DuckZ/wrenpp.git
revision = ebca413c0a3e885ac1901bd555e127476c40b057
[provide]
wrenpp = wrenpp_dep
dependency_names = wrenpp-0.2.0
```
This will make Wrenpp build as part of your project with Wren's optional random
module enabled.
@ -143,11 +99,19 @@ wrenpp_dep = dependency('wrenpp', version: '>=0.1.0',
)
```
Note that when you use Wrenpp as a subproject, Wrenpp's subproject Wren will
become a sub-subproject of your project. This is how Meson works and it simply
means that in your top level source directory you will have to run this command
before you will be able to compile (Meson should detect and print this as
well):
```
meson wrap promote subprojects/wrenpp/subprojects/wren
```
### C++ ###
For working examples refer to the source files in the `examples/` directory.
"Greet" is the simplest example, while "math_vector" is showing off more
features.
#### Header files ####
@ -164,8 +128,8 @@ at least. A description of all the relevant header files follows:
* `def_configuration.hpp` The `DefConfiguration` struct extends the bare
`Configuration` struct by providing an implementation for `write_fn`,
`error_fn` and `reallocate_fn`. They are implemented in terms of `std::cout`,
`std::cerr` and `std::realloc`/`std::free` respectively. You can safely ignore
this header if this is not suitable for your project.
`std::cerr` and `new[]`/`delete[]` respectively. You can safely ignore this
header if this is not suitable for your project.
Other header files are intended for Wrenpp's use and you shouldn't need to use
them. You are free to use them in your project if you think the code inside is
@ -191,87 +155,4 @@ int main() {
}
```
#### Foreign functions ####
You have two options to register foreign functions with wrenpp: the easiest one
is to just use the callback manager available through the `VM` object:
```
#include <wrenpp/vm.hpp>
#include <wrenpp/def_configuration.hpp>
#include <wrenpp/callback_manager.hpp> //necessary if you want to use the callback manager
int main() {
wren::DefConfiguration config;
wren::VM vm(&config, nullptr);
vm.callback_manager()
.add_callback(true, "your_module", "YourClass", "your_method(_,_)", &your_method);
vm.interpret("main", your_fun_script_here);
return 0;
}
```
The current implementation available in `DefConfiguration` registers a callback
to Wren that looks up a `std::unordered_map` for the correct c++ function and
then forwards the call to it. This should be good enough for most cases,
however you are free to provide your own callback for wren by writing your own
Configuration class. Wrenpp tries to not impose you any particular helper code,
in fact if you don't wish to use the `CallbackManager` returned by
`vm.callback_manager()` then you don't even need to include the relative header
file! There will still be a `std::unordered_map` in memory (because that's
owned by `vm`) but it will never be used.
The second method requires you to provide the full Wren foreign functions
callback:
```
#include <wrenpp/vm.hpp>
#include <wrenpp/def_configuration.hpp>
class MyConf : public wren::DefConfiguration {
public:
//This is the callback that Wren will call, refer to the C API documentation
//for more details.
wren::foreign_method_t foreign_method_fn(
wren::VM* vm,
std::string_view module,
std::string_view class_name,
bool is_static,
std::string_view signature
) {
if (module == "your_module" and class_name == "YourClass") {
if (is_static and signature == "your_method(_,_)")
return &your_method;
}
return nullptr;
}
}
int main() {
MyConf config;
wren::VM vm(&config, nullptr);
vm.interpret("main", your_fun_script_here);
return 0;
}
```
The above code is very close to what you'd do with the C API. If you need, you
can even pass a user data pointer to the `VM` constructor (`nullptr` in this
snippet) and retrieve it later from within `foreign_method_fn()` via
`vm.void_user_data()` or `vm.user_data()`. You're unlikely to need it as, as
you can see, `foreign_method_fn()` is not static and so you can have some state
stored in your `MyConf` object, however you still get the chance to use the
C-like user data mechanism if you wish to.
Note that for the above to work the `foreign_method_fn()` method in `MyConf`
must be named exactly like that, and the signature must match (except for the
`static` and `const` keywords). Ideally the code above should alse be
`noexcept` as there will be C code in the call stack when that method is
invoked.
## Implementation ##
*Work in progress*

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,8 +17,6 @@
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/callback_manager.hpp"
#include "wrenpp/class_manager.hpp"
#include <string_view>
#include <algorithm>
#include <ctime>
@ -69,7 +67,7 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
}
}
static void today (wren::VM& vm, wren::ModuleAndName) {
static void today (wren::VM& vm) {
vm.set_slot_string(0, today_unique_str().get());
}
@ -99,36 +97,54 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
class MyConf : public wren::DefConfiguration {
public:
char* load_module_fn(wren::VM* vm, std::string_view module_name) {
if (module_name == "calendar") {
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 = new char[buff_sz];
char* const buff = static_cast<char*>(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;
}
void load_module_complete_fn(wren::VM*, std::string_view, char* buffer) {
delete[] buffer;
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>();
else if (not is_static and signature == "appointment_count()")
return wren::make_method_bindable<&Calendar::appointment_count>();
}
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<Calendar>();
}
else {
return {nullptr, nullptr};
}
}
};
} //unnamed namespace
int main() {
using wren::MN;
typedef wren::ModuleAndName MN;
MyConf conf;
wren::VM vm(&conf, nullptr);
vm.callback_manager()
.add_callback(true, "calendar", "Calendar", "today()", [](){return &Calendar::today;})
.add_callback(false, "calendar", "Calendar", "add_appointment(_)", wren::make_function_bindable<&Calendar::add_appointment>)
.add_callback(false, "calendar", "Calendar", "appointment_count()", wren::make_function_bindable<&Calendar::appointment_count>);
vm.class_manager().add_class_maker("calendar", "Calendar", wren::make_foreign_class<Calendar>);
vm.interpret("main", g_test_script);
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN<"main", "cale">)).data();
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN{"main", "cale"}));
cale->print_appointments();
return 0;

View file

@ -1,219 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/callback_manager.hpp"
#include "wrenpp/class_manager.hpp"
#include <chrono>
#include <thread>
#include <iostream>
namespace {
constexpr char g_module_a[] =
"foreign class ClassA {" R"script(
construct new(msg) {
System.print("Wren ClassA constructed")
}
foreign say_hi()
}
)script";
constexpr char g_module_b[] = ""
R"script(
import "module_a" for ClassA
foreign class ClassB {
construct new(nickname) {
System.print("Wren ClassB constructed")
}
do_action(obj_a, times) {
System.print("Wren ClassB is doing its action %(times) times...")
for (z in 1..times) {
obj_a.say_hi()
}
greeting_message("John", "Doe", "\\(O.O)/")
}
foreign greeting_message(first_name, family_name, emoji)
foreign set_obj_c (obj)
foreign get_obj_c()
}
)script";
constexpr char g_module_c[] =
"foreign class ClassC {" R"script(
construct new (msg) {}
foreign print_message()
}
)script";
//This is several examples in one:
//1. instantiate ClassA in Wren and pass it to do_action() which is a
// non-foreign method in wren
//2. instantiate ClassA in C++, have C++ invoke the non-foreign method
// do_action() on the object obj_b from the previous execution and pass the
// C++ instance of ClassA to it
//3. instantiate ClassB in C++, have C++ invoke the non-foreign method
// do_action() on it and pass the same ClassA instance from the previous
// step to it
//4. show how to return a pre-existing instance of ClassC from ClassB both in
// C++ and Wren
constexpr char g_script[] = ""
R"script(
import "module_a" for ClassA
import "module_b" for ClassB
import "module_c" for ClassC
var obj_b = ClassB.new("TheWren")
obj_b.do_action(ClassA.new("instanciated from script"), 2)
obj_b.greeting_message("Jane", "Doe", "ʕ·͡ᴥ·ʔ")
var obj_c = ClassC.new("Message of ClassC object instantiated in Wren")
obj_b.set_obj_c(obj_c)
obj_b.get_obj_c().print_message()
)script";
class MyWrenConfig : public wren::DefConfiguration {
public:
char* load_module_fn (wren::VM* vm, std::string_view module_name) {
if (module_name == "module_a")
return copied(g_module_a, sizeof(g_module_a));
else if (module_name == "module_b")
return copied(g_module_b, sizeof(g_module_b));
else if (module_name == "module_c")
return copied(g_module_c, sizeof(g_module_c));
return nullptr;
}
void load_module_complete_fn (wren::VM* vm, std::string_view module_name, char* buff) {
static_cast<void>(vm);
static_cast<void>(module_name);
delete[] buff;
}
private:
char* copied (const char* source, std::size_t len) {
char* const buff = new char[len];
std::copy(source, source + len / sizeof(source[0]), buff);
return buff;
}
};
struct ClassA {
explicit ClassA (std::string msg) : m_message(msg) {
std::cout << "C++ ClassA constructed\n";
}
ClassA (const ClassA&) = delete;
ClassA (ClassA&&) = delete;
void say_hi() {
std::cout << "C++ ClassA says \"" << m_message << "\"!\n";
}
std::string m_message;
};
class ClassC;
class ClassB {
public:
explicit ClassB (std::string nickname) : m_nickname(nickname) {
std::cout << "C++ ClassB constructed\n";
}
ClassB (const ClassB&) = delete;
ClassB (ClassB&&) = delete;
void greeting_message (
std::string_view first_name,
const char* family_name,
const std::string& emoji
) {
std::cout << "C++ ClassB says \"hello " << first_name << " '" <<
m_nickname << "' " << family_name << "\" " << emoji << '\n';
}
void set_obj_c (wren::ForeignObject<ClassC> obj) {
m_obj_c = std::move(obj);
}
wren::ForeignObject<ClassC>* get_obj_c() { return &m_obj_c; }
private:
std::string m_nickname;
wren::ForeignObject<ClassC> m_obj_c;
};
class ClassC {
public:
ClassC (std::string msg) : m_message(msg) {}
void print_message() const { std::cout << m_message << '\n'; }
private:
std::string m_message;
};
} //unnamed namespace
int main() {
using wren::make_function_bindable;
using wren::make_foreign_class;
using wren::make_wren_object;
//We need a custom one to deal with custom module loading for
//module_a and module_b
MyWrenConfig config;
wren::VM vm(&config, nullptr);
vm.callback_manager()
.add_callback(false, "module_a", "ClassA", "say_hi()", make_function_bindable<&ClassA::say_hi>)
.add_callback(false, "module_b", "ClassB", "greeting_message(_,_,_)", make_function_bindable<&ClassB::greeting_message>)
.add_callback(false, "module_b", "ClassB", "set_obj_c(_)", make_function_bindable<&ClassB::set_obj_c>)
.add_callback(false, "module_b", "ClassB", "get_obj_c()", make_function_bindable<&ClassB::get_obj_c>)
.add_callback(false, "module_c", "ClassC", "print_message()", make_function_bindable<&ClassC::print_message>)
;
vm.class_manager()
.add_class_maker("module_b", "ClassB", make_foreign_class<ClassB, std::string>)
.add_class_maker("module_a", "ClassA", make_foreign_class<ClassA, std::string>)
.add_class_maker("module_c", "ClassC", make_foreign_class<ClassC, std::string>)
;
//Example 1: invoke obj_b.do_action() from Wren passing an obj_a that's
//also instantiated from within the Wren script
vm.interpret("main", g_script);
//Example 2: invoke obj_b.do_action() from C++ passing a new obj_a which
//is instantiated from C++
wren::ForeignObject<ClassA> obj_a = make_wren_object<ClassA>(vm, wren::MN<"module_a", "ClassA">, "instantiated from c++");
wren::call<void>(vm, wren::MN<"main", "obj_b">, "do_action", obj_a, 3);
//Example 3: invoke obj_b.do_action() from C++, where obj_b is also
//instantiated from C++, and pass the C++ obj_a instance to it
auto obj_b = make_wren_object<ClassB>(vm, wren::MN<"module_b", "ClassB">, "TheCpp");
wren::call<void>(vm, obj_b, "do_action", obj_a, 4);
//Example 4: set obj_c on obj_c and query it back
wren::ForeignObject<ClassC> obj_c = make_wren_object<ClassC>(vm, wren::MN<"module_c", "ClassC">, "Message of ClassC object instantiated in C++");
obj_b.object().set_obj_c(std::move(obj_c));
obj_b.object().get_obj_c()->object().print_message();
std::cout << "Quitting in 1 sec" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 0;
}

View file

@ -1,5 +0,0 @@
executable('cpp_calls',
'main.cpp',
dependencies: wrenpp_dep,
install: false,
)

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,7 +17,6 @@
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/callback_manager.hpp"
#include <iostream>
#include <string>
#include <fstream>
@ -37,17 +36,50 @@ namespace {
std::uniform_int_distribution<int> distrib;
};
void user_input(wren::VM& vm, wren::ModuleAndName) {
void user_input(wren::VM& vm) {
std::string retval;
std::cin >> retval;
set(vm, 0, retval);
}
void random_num(wren::VM& vm, wren::ModuleAndName) {
void random_num(wren::VM& vm) {
auto* const cust_data = vm.user_data<CustomData>();
set(vm, 0, cust_data->distrib(cust_data->generator));
}
class MyConfig : public wren::DefConfiguration {
public:
wren::foreign_method_t foreign_method_fn (
wren::VM* vm,
const char* module_ptr,
const char* class_name_ptr,
bool is_static,
const char* signature_ptr
) {
std::string_view module(module_ptr);
std::string_view class_name(class_name_ptr);
std::string_view signature(signature_ptr);
//std::cout << "requested: \"" << module << "\" \"" <<
// class_name << "\" \"" << signature << "\" static: " <<
// std::boolalpha << is_static << '\n';
if ("main" == module) {
if ("Game" == class_name) {
if ("user_input()" == signature and is_static)
return &user_input;
else if ("random()" == signature and is_static)
return &random_num;
}
}
return nullptr;
}
//char* load_module_fn (wren::VM* vm, const char* name) {
// std::cout << "asked to load module \"" << name << "\"\n";
// return nullptr;
//}
};
std::string load_file (const std::string& path) {
std::ifstream ifs(path);
ifs >> std::noskipws;
@ -63,13 +95,10 @@ int main() {
std::random_device rand_dev;
CustomData custom_data(rand_dev());
wren::DefConfiguration config;
MyConfig config;
wren::VM vm(&config, &custom_data);
vm.callback_manager().add_callback(true, "main", "Game", "user_input()", [](){return &user_input;})
.add_callback(true, "main", "Game", "random()", [](){return &random_num;});
interpret(vm, "main", load_file("main.wren"));
wren::call<void>(vm, wren::MN<"main", "the_game">, "play_game");
wren::call<void>(vm, {"main", "the_game"}, "play_game");
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 0;

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,11 +17,9 @@
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/callback_manager.hpp"
#include <chrono>
#include <thread>
#include <unistd.h>
#include <iostream>
#if defined(__GNU_LIBRARY__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2)
# define HasSecureGetenv
@ -57,19 +55,39 @@ const char* raw_fetch_env (const char* name) noexcept {
return val_ptr;
}
void user_get_env (wren::VM& vm, wren::ModuleAndName) {
void user_get_env (wren::VM& vm) {
set(vm, 0, raw_fetch_env(wren::get<const char*>(vm, 1)));
}
class MyConfig : public wren::DefConfiguration {
public:
wren::foreign_method_t foreign_method_fn (
wren::VM* vm,
const char* module_ptr,
const char* class_name_ptr,
bool is_static,
const char* signature_ptr
) {
//std::cout << "VM " << vm << " requested foreign method " << class_name << "::" << signature << " in module " << module << "\n";
std::string_view module(module_ptr);
std::string_view class_name(class_name_ptr);
std::string_view signature(signature_ptr);
if ("User" == class_name and "main" == module and "get_env(_)" == signature)
return &user_get_env;
return nullptr;
}
};
} //unnamed namespace
int main() {
wren::DefConfiguration config;
wren::VM vm(&config, nullptr);
vm.callback_manager().add_callback(true, "main", "User", "get_env(_)", [](){return &user_get_env;});
//typedef wren::ModuleAndName MN;
MyConfig config;
wren::VM vm(&config, nullptr);
vm.interpret("main", g_script);
wren::call<void>(vm, wren::MN<"main", "the_user">, "greet");
wren::call<void>(vm, {"main", "the_user"}, "greet");
std::cout << "Quitting in 1 sec" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));

View file

@ -1,134 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/callback_manager.hpp"
#include "wrenpp/class_manager.hpp"
#include <string_view>
#include <algorithm>
#include <iostream>
namespace {
constexpr std::string_view g_math_vector_src{
"foreign class MathVector {" R"script(
construct new() {}
construct new(value) {}
construct new(x, y, z) {}
foreign x
foreign y
foreign z
foreign x=(value)
foreign y=(value)
foreign z=(value)
foreign static base_x()
}
)script"};
constexpr const char g_test_script[] =
R"script(import "math_vector" for MathVector
var vec1 = MathVector.new(15.0)
var vec2 = MathVector.new(10.0, 20.0, 30.0)
var vec3 = MathVector.new()
System.print("vec1 constructed from single value: <%(vec1.x), %(vec1.y), %(vec1.z)>")
System.print("vec2 constructed from three values: <%(vec2.x), %(vec2.y), %(vec2.z)>")
System.print("vec3 default constructed: <%(vec3.x), %(vec3.y), %(vec3.z)>")
vec3.x = 3.5
vec3.y = vec2.x / vec2.z
vec3.z = vec1.x + vec2.y / 4.0
System.print("vec3 modified by scripting: <%(vec3.x), %(vec3.y), %(vec3.z)>")
var vec_base_x = MathVector.base_x()
System.print("vec_base_x modified by scripting: <%(vec_base_x.x), %(vec_base_x.y), %(vec_base_x.z)>")
)script";
template <typename T>
class Vector {
public:
Vector() = default;
explicit Vector (T value) :
m_x(value), m_y(value), m_z(value)
{}
Vector (T x, T y, T z) :
m_x(x), m_y(y), m_z(z)
{}
~Vector() noexcept = default;
T x() const { return m_x; }
T y() const { return m_y; }
T z() const { return m_z; }
void set_x(T x) { m_x = x; }
void set_y(T y) { m_y = y; }
void set_z(T z) { m_z = z; }
static Vector base_x() { return {1.0, 0.0, 0.0}; }
private:
T m_x{}, m_y{}, m_z{};
};
class MyConf : public wren::DefConfiguration {
public:
char* load_module_fn(wren::VM* vm, std::string_view module_name) {
if (module_name == "math_vector") {
constexpr const std::size_t buff_sz = g_math_vector_src.size() + 1;
char* const buff = new char[buff_sz];
std::copy(g_math_vector_src.cbegin(), g_math_vector_src.cend(), buff);
buff[buff_sz - 1] = '\0';
return buff;
}
return nullptr;
}
void load_module_complete_fn(wren::VM*, std::string_view, char* buffer) {
delete[] buffer;
}
};
} //unnamed namespace
int main() {
using wren::make_function_bindable;
using wren::make_foreign_class;
using wren::ConstructorParameters;
MyConf conf;
wren::VM vm(&conf, nullptr);
vm.callback_manager()
.add_callback(false, "math_vector", "MathVector", "x=(_)", make_function_bindable<&Vector<double>::set_x>)
.add_callback(false, "math_vector", "MathVector", "y=(_)", make_function_bindable<&Vector<double>::set_y>)
.add_callback(false, "math_vector", "MathVector", "z=(_)", make_function_bindable<&Vector<double>::set_z>)
.add_callback(false, "math_vector", "MathVector", "x", make_function_bindable<&Vector<double>::x>)
.add_callback(false, "math_vector", "MathVector", "y", make_function_bindable<&Vector<double>::y>)
.add_callback(false, "math_vector", "MathVector", "z", make_function_bindable<&Vector<double>::z>)
.add_callback(true, "math_vector", "MathVector", "base_x()", make_function_bindable<&Vector<double>::base_x>);
vm.class_manager()
.add_class_maker("math_vector", "MathVector", make_foreign_class<Vector<double>,
double, //single value constructor
ConstructorParameters<double, double, double>, //x,y,z constructor
ConstructorParameters<> //default constructor
>);
vm.interpret("main", g_test_script);
return 0;
}

View file

@ -1,6 +0,0 @@
executable('math_vector',
'main.cpp',
dependencies: wrenpp_dep,
install: false,
)

View file

@ -1,5 +1,3 @@
subdir('dieroll')
subdir('greet')
subdir('calendar')
subdir('math_vector')
subdir('cpp_calls')

View file

@ -1 +0,0 @@
subdir('wrenpp')

View file

@ -0,0 +1,148 @@
#ifndef id42C91D2875AE4E56BA61051619B58C03
#define id42C91D2875AE4E56BA61051619B58C03
#include <cstdint>
#include <cstddef>
namespace duckcore {
class StringCRC32 {
struct FnvHashBase {
[[gnu::pure]] [[gnu::always_inline]]
static uint32_t Calculate ( const char parChar, uint32_t parCrc );
};
//Update step: crc_32_tab[(crc ^ ch) & 0xff] ^ (crc >> 8)
template <uint32_t N, uint32_t I>
struct FnvHash : private FnvHashBase {
[[gnu::always_inline]]
static uint32_t Calculate ( const char (&str)[N], uint32_t crc ) {
const uint32_t prevcrc = FnvHash<N, I-1>::Calculate(str, crc);
return FnvHashBase::Calculate(str[I-1], prevcrc);
}
};
template <unsigned int N>
struct FnvHash<N, 1> : private FnvHashBase {
[[gnu::always_inline]]
static uint32_t Calculate ( const char (&str)[N], uint32_t crc ) {
return FnvHashBase::Calculate(str[0], crc);
}
};
class ConstCharWrapper {
public:
ConstCharWrapper ( const char* parStr ) : str(parStr) { }
const char* const str;
};
public:
StringCRC32 ( ConstCharWrapper parStr );
template <unsigned int N>
[[gnu::always_inline]]
StringCRC32 ( const char (&str)[N] ) :
m_hash(~FnvHash<N, N>::Calculate(str, 0xffffffff))
{
}
operator uint32_t ( void ) const { return m_hash; }
private:
uint32_t m_hash;
private:
//This is meant to represent a list of bits that are set to 1
template <int N, typename T>
struct BitArray {
enum { value = N };
typedef T Next;
};
//Polynomial from zlib: {0,1,2,4,5,7,8,10,11,12,16,22,23,26} or 0xedb88320UL
// for (int poly = 0, n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
// poly |= (z_crc_t)1 << (31 - p[n]);
typedef BitArray<0, BitArray<1, BitArray<2, BitArray<4, BitArray<5,
BitArray<7, BitArray<8, BitArray<10, BitArray<11, BitArray<12,
BitArray<16, BitArray<22, BitArray<23,
BitArray<26, nullptr_t> > > > > > > > > > > > > > PolynomialBits;
template <typename P, int M>
struct MakePolynomial {
enum { value = (1 << (M - P::value)) bitor MakePolynomial<typename P::Next, M>::value };
};
template <int M>
struct MakePolynomial<nullptr_t, M> {
enum { value = 0 };
};
//CRC32 algorithm from zlib:
// for (int n = 0; n < 256; n++) {
// c = n;
// for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1;
// crc_table[n] = c;
// }
template <int C, int S=8, uint32_t P=static_cast<uint32_t>(MakePolynomial<PolynomialBits, 31>::value)>
struct TableLookup {
static_assert(S > 1);
enum {
poly = P,
value = TableLookup<TableLookup<C, S-1, poly>::value, 1, poly>::value
};
};
template <int C, uint32_t P>
struct TableLookup<C, 1, P> {
enum {
poly = P,
value = ((C & 1) == 1 ? poly ^ (static_cast<uint32_t>(C) >> 1) : static_cast<uint32_t>(C) >> 1)
};
};
};
inline uint32_t StringCRC32::FnvHashBase::Calculate (const char parChar, uint32_t parCrc) {
static const uint32_t crc_32_tab[256] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
return crc_32_tab[(parCrc ^ parChar) & 0xff] ^ (parCrc >> 8);
}
} //namespace duckcore
#endif

View file

@ -1,126 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "detail/wren_types.hpp"
#include "detail/strings_in_vector.hpp"
#include <unordered_map>
#include <vector>
#include <string_view>
#include <type_traits>
#include <functional>
namespace wren::detail {
class FullSignatureOwning;
} //namespace wren::detail
namespace std {
template <>
struct hash<wren::detail::FullSignatureOwning> {
std::size_t operator() (const wren::detail::FullSignatureOwning& key) const;
};
};
namespace wren {
namespace detail {
class FullSignatureBase {
public:
FullSignatureBase (const FullSignatureBase& other) :
m_module_hash(other.m_module_hash),
m_class_name_hash(other.m_class_name_hash),
m_signature_hash(other.m_signature_hash)
{ }
std::size_t module_hash() const { return m_module_hash; }
std::size_t class_hash() const { return m_class_name_hash; }
std::size_t signature_hash() const { return m_signature_hash; }
protected:
FullSignatureBase (std::size_t module_hash_v, std::size_t class_hash_v, std::size_t signature_hash_v) :
m_module_hash(module_hash_v),
m_class_name_hash(class_hash_v),
m_signature_hash(signature_hash_v)
{ }
private:
std::size_t m_module_hash;
std::size_t m_class_name_hash;
std::size_t m_signature_hash;
};
class FullSignatureOwning : public FullSignatureBase, private StringsInVector<3> {
public:
FullSignatureOwning (std::string_view module_name, std::string_view class_name, std::string_view signature);
std::string_view module_name() const { return as_string_view<0>(); }
std::string_view class_name() const { return as_string_view<1>(); }
std::string_view signature() const { return as_string_view<2>(); }
};
//Temp because it's only supposed to be used to store temporaries
//It will contain a dangling reference if the FullSignatureOwning object
//used to initialise an object of this class gets destroyed
class TempFullSignature : public FullSignatureBase {
public:
TempFullSignature (const FullSignatureOwning& mn);
TempFullSignature (std::string_view module_name, std::string_view class_name, std::string_view signature);
std::string_view module_name() const { return m_module_name; }
std::string_view class_name() const { return m_class_name; }
std::string_view signature() const { return m_signature; }
private:
std::string_view m_module_name;
std::string_view m_class_name;
std::string_view m_signature;
};
struct FullSignatureEqual {
using is_transparent = std::true_type;
bool operator()(TempFullSignature left, TempFullSignature right) const;
};
struct FullSignatureHash {
using is_transparent = std::true_type;
std::size_t operator()(TempFullSignature value) const;
};
} //namespace detail
class CallbackManager {
typedef std::unordered_map<detail::FullSignatureOwning, foreign_method_t, detail::FullSignatureHash, detail::FullSignatureEqual> MethodMap;
public:
CallbackManager();
~CallbackManager() noexcept;
CallbackManager& add_callback (
bool is_static,
std::string_view module_name,
std::string_view class_name,
std::string_view signature,
std::function<foreign_method_t()> make_cb
);
foreign_method_t callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature) const;
private:
MethodMap* method_map (bool is_static) noexcept;
const MethodMap* method_map (bool is_static) const noexcept;
MethodMap m_static_methods;
MethodMap m_normal_methods;
};
} //namespace wren

View file

@ -1,151 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "detail/wren_types.hpp"
#include "detail/strings_in_vector.hpp"
#include "detail/construct_foreign_class.hpp"
#include "detail/wren_class_name_from_type.hpp"
#include "detail/type_id.hpp"
#include <unordered_map>
#include <string>
#include <type_traits>
#include <functional>
#include <utility>
namespace wren {
namespace detail {
class ClassNameBase {
public:
ClassNameBase (const std::string_view& module_name, const std::string_view& class_name);
ClassNameBase (const ClassNameBase& other) = default;
std::size_t module_hash() const noexcept { return m_module_hash; }
std::size_t class_hash() const noexcept { return m_class_name_hash; }
bool operator== (const ClassNameBase& other) const;
private:
std::size_t m_module_hash;
std::size_t m_class_name_hash;
};
class ClassNameOwning : StringsInVector<2>, public ClassNameBase {
public:
ClassNameOwning (const std::string_view& module_name, const std::string_view& class_name);
std::string_view module_name() const { return this->as_string_view<0>(); }
std::string_view class_name() const { return this->as_string_view<1>(); }
operator ModuleAndName() const;
using StringsInVector<2>::operator<;
bool operator== (const ClassNameOwning& other) const;
};
class TempClassName : public ClassNameBase {
public:
TempClassName (std::string_view module_name, std::string_view class_name);
TempClassName (const ClassNameOwning& model);
bool operator== (const TempClassName& other) const;
std::string_view module_name() const { return m_module_name; }
std::string_view class_name() const { return m_class_name; }
private:
std::string_view m_module_name, m_class_name;
};
struct ClassNameEqual {
using is_transparent = std::true_type;
bool operator()(TempClassName left, TempClassName right) const;
};
struct ClassNameHash {
using is_transparent = std::true_type;
std::size_t operator()(TempClassName value) const;
};
class TypeIDHash {
public:
std::size_t operator()(TypeID tid) const;
};
define_has_typedef(class_type, ClassType);
} //namespace detail
//Customisation point - specialise for your own types if needed
template <typename T>
struct ClassMakerTraits {
};
template <typename T, typename... Args>
struct ClassMakerTraits<detail::MakeForeignClass<T, Args...>> {
typedef T class_type;
};
class ClassManager {
typedef std::function<foreign_class_t()> make_foreign_class_t;
typedef std::unordered_map<detail::ClassNameOwning, make_foreign_class_t, detail::ClassNameHash, detail::ClassNameEqual> ClassMap;
typedef std::unordered_map<TypeID, const detail::ClassNameOwning*, detail::TypeIDHash> TypeMap;
public:
ClassManager();
~ClassManager() noexcept;
template <typename F>
ClassManager& add_class_maker (std::string module_name, std::string_view class_name, F&& maker);
foreign_class_t make_class(std::string_view module_name, std::string_view class_name);
ModuleAndName wren_class_name_from_hash(TypeID hash) const;
template <typename T>
ModuleAndName wren_class_name_from_type() const;
private:
ClassMap::const_iterator add_class_maker_implem (
std::string_view module_name,
std::string_view class_name,
make_foreign_class_t
);
void add_type (TypeID hash, const detail::ClassNameOwning* name);
ClassMap m_classes;
TypeMap m_types; //refers to memory in m_classes
};
template <typename F>
inline ClassManager& ClassManager::add_class_maker (std::string module_name, std::string_view class_name, F&& maker) {
typedef ClassMakerTraits<std::decay_t<F>> MakerTraits;
auto it_new = this->add_class_maker_implem(module_name, class_name, std::forward<F>(maker));
//See if we can deduce the class type that maker is supposed to work
//with. This is not guaranteed to be an existing piece of info because
//user code can provide their own function that doesn't use any actual
//c++ class, just normal functions.
if constexpr (detail::HasClassTypeTypedef<MakerTraits>::value) {
const auto& owning_name = it_new->first;
this->add_type(type_id<typename MakerTraits::class_type>(), &owning_name);
}
return *this;
}
template <typename T>
inline ModuleAndName ClassManager::wren_class_name_from_type() const {
return detail::wren_class_name_from_type<T>(*this);
}
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -18,16 +18,17 @@
#pragma once
#include "configuration.hpp"
#include "detail/wren_types.hpp"
#include "detail/error_type.hpp"
#include "error_type.hpp"
namespace wren {
class VM;
typedef void(*foreign_method_t)(VM&);
class DefConfiguration : public Configuration {
public:
static void write_fn (VM*, wren_string_t text);
static void error_fn (VM*, ErrorType, wren_string_t module_name, int line, wren_string_t msg);
static void write_fn (VM*, const char* text);
static void error_fn (VM*, ErrorType, const char* module, int line, const char* msg);
static void* reallocate_fn(void* ptr, std::size_t size);
static foreign_method_t foreign_method_fn (VM* vm, wren_string_t module_name, wren_string_t class_name, bool is_static, wren_string_t signature);
static foreign_class_t foreign_class_fn (wren::VM* vm, std::string_view module_name, std::string_view class_name);
};
} //namespace wren

View file

@ -1,175 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../vm.hpp"
#include "setters_getters.hpp"
#if defined(WRENPP_WITH_NAME_GUESSING)
# include "guess_class_name.hpp"
#endif
#include <utility>
#include <cassert>
#include <cstdint>
namespace wren {
template <typename... Args> struct ConstructorParameters { };
namespace detail {
template <typename T, typename... Args, int... Indices>
inline void construct_single (
std::integer_sequence<int, Indices...>,
VM& vm,
void* memory
) {
new(memory) T{get<Args>(vm, Indices + 1)...};
}
struct ConstructResult {
std::uint16_t parameter_count;
bool success;
};
template <typename T, typename... Args>
struct ForeignClassHelper;
template <typename T, typename... PackArgs, typename... Args>
struct ForeignClassHelper<T, ConstructorParameters<PackArgs...>, Args...> {
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
using std::make_integer_sequence;
//search by number of parameters.
//once we find a ConstructorParameters that contains the right
//number of types we invoke construct_single() with those types.
constexpr int pack_size = static_cast<int>(sizeof...(PackArgs));
if (pack_size == cardinality) {
construct_single<T, PackArgs...>(make_integer_sequence<int, pack_size>{}, vm, memory);
return ConstructResult{pack_size, true};
}
else {
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
}
}
};
template <typename T, typename LoneArg, typename... Args>
struct ForeignClassHelper<T, LoneArg, Args...> {
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
using std::make_integer_sequence;
if (1 == cardinality) {
construct_single<T, LoneArg>(make_integer_sequence<int, 1>{}, vm, memory);
return ConstructResult{1, true};
}
else {
if constexpr (sizeof...(Args) > 0) {
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
}
else {
return ConstructResult{0, false};
}
}
}
};
template <typename T>
struct ForeignParamHelper {
static constexpr std::size_t argument_count = 1;
};
template <template <typename...> class Pack, typename... PackArgs>
struct ForeignParamHelper<Pack<PackArgs...>> {
static constexpr std::size_t argument_count = sizeof...(PackArgs);
};
template <typename T>
struct ForeignClassHelper<T> {
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
using std::make_integer_sequence;
if (cardinality == 0) {
construct_single<T>(make_integer_sequence<int, 0>{}, vm, memory);
return ConstructResult{0, true};
}
else {
return ConstructResult{static_cast<std::uint16_t>(cardinality), false};
}
}
};
template <std::size_t Search, std::size_t... Values>
struct AssertIfDuplicateValues {
static_assert(sizeof...(Values) == 0, "Code bug?");
};
template <std::size_t Search, std::size_t Value, std::size_t... Values>
struct AssertIfDuplicateValues<Search, Value, Values...> : AssertIfDuplicateValues<Search, Values...>, AssertIfDuplicateValues<Value, Values...> {
static_assert(Search != Value, "Constructor overloads with the same argument counts are not currently allowed");
static constexpr std::size_t value = 1;
};
template <typename... Args>
constexpr void static_assert_all_packs_are_unique() {
//If more than one arg (ctor overload) is given, check they are unique
if constexpr (sizeof...(Args) > 1) {
constexpr auto dummy = AssertIfDuplicateValues<ForeignParamHelper<Args>::argument_count...>::value;
static_assert(dummy == 1); //always true
}
}
//This is named from the perspective of the user - they say
//MakeForeignClass<X> and it will "produce" object of type X. In
//reality it produces a functor that does that, and it's that functor
//that gets registered into wren, so from the library perspective it
//should be called MakeForeignClassMaker
template <typename T, typename... Args>
class MakeForeignClass {
public:
MakeForeignClass() = default;
foreign_class_t operator()() const {
detail::static_assert_all_packs_are_unique<Args...>();
foreign_class_t ret;
ret.allocate = [](VM& vm, ModuleAndName mn) {
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
const auto result = detail::ForeignClassHelper<T, Args...>::construct(vm, vm.slot_count() - 1, mem);
if (not result.success) {
abort_fiber_with_error(vm, 1,
std::string{"No registered c++ constructor "} +
#if defined(WRENPP_WITH_NAME_GUESSING)
"for class " + guess_class_name<T>() + " " +
#endif
"takes " + std::to_string(result.parameter_count) +
" parameter" + (result.parameter_count == 1 ? "" : "s")
);
}
};
ret.finalize = [](void* mem) {
const auto cale = static_cast<T*>(mem);
cale->~T();
};
return ret;
}
};
} //namespace detail
template <typename T, typename... Args>
constexpr detail::MakeForeignClass<T, Args...> make_foreign_class;
} //namespace wren

View file

@ -1,97 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include <utility>
namespace wren {
namespace detail {
[[gnu::const]]
std::uint32_t runtime_crc32c (const char* data, std::size_t size, std::uint32_t crc);
constexpr std::uint32_t g_castagnoli_polynomial = 0x1EDC6F41;
[[gnu::const]]
constexpr std::uint8_t reverse (std::uint8_t b) {
//see https://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
}
[[gnu::const]]
constexpr std::uint32_t reverse (std::uint32_t val) {
return (reverse(static_cast<std::uint8_t>(val & 0xff)) << 24) |
(reverse(static_cast<std::uint8_t>(val >> 8 & 0xff)) << 16) |
(reverse(static_cast<std::uint8_t>(val >> 16 & 0xff)) << 8) |
reverse(static_cast<std::uint8_t>(val >> 24 & 0xff));
}
consteval std::uint32_t calc_table_entry (std::uint32_t index, std::uint32_t polynomial) {
polynomial = reverse(polynomial);
auto c = static_cast<std::uint_fast32_t>(index);
for (std::uint_fast32_t k = 0; k < 8; ++k) {
c = (c >> 1) ^ ((c & 0x1u) ? polynomial : 0);
}
return static_cast<std::uint32_t>(c);
}
template <std::uint32_t Polynomial, typename T>
struct PolynomialTableBase;
template <std::uint32_t Polynomial, std::uint32_t... Indices>
struct PolynomialTableBase<Polynomial, std::integer_sequence<std::uint32_t, Indices...>> {
static constexpr std::size_t table_size = sizeof...(Indices);
static constexpr std::uint32_t table[table_size] = {calc_table_entry(Indices, Polynomial)...};
};
template <std::uint32_t Polynomial>
struct PolynomialTable : public PolynomialTableBase<Polynomial, decltype(std::make_integer_sequence<std::uint32_t, 256>{})> {
};
template <std::uint32_t Polynomial>
constexpr inline auto g_polynomial_table = PolynomialTable<Polynomial>::table;
template <std::uint32_t Polynomial, std::uint32_t XorIn=0xffffffff, std::uint32_t XorOut=XorIn>
constexpr std::uint32_t crc32 (const char* data, std::size_t len, std::uint32_t crc) noexcept {
//static_assert(g_polynomial_table<Polynomial>[0b10000000] == Polynomial);
crc ^= XorIn;
for (std::size_t z = 0; z < len; ++z) {
crc = g_polynomial_table<Polynomial>[(crc ^ static_cast<unsigned char>(data[z])) & 0xff] ^ (crc >> 8);
}
return crc ^ XorOut;
}
} //namespace detail
[[gnu::const]]
constexpr std::uint32_t crc32c (const char* data, std::size_t size) {
if (not std::is_constant_evaluated()) {
return detail::runtime_crc32c(data, size, 0);
}
else {
return detail::crc32<detail::g_castagnoli_polynomial>(data, size, 0);
}
}
template <typename T, std::size_t N>
[[gnu::const]]
constexpr std::uint32_t crc32c (const T (&data)[N]) {
return crc32c(static_cast<const char*>(data), N * sizeof(T));
}
} //namespace wren

View file

@ -1,42 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <type_traits>
namespace wren::detail {
//Dereferences the given parameter if necessary, always returning an optionally
//cv-qualified ref
template <typename T>
struct DerefIFN {
static typename std::remove_reference<T>::type& deref (
typename std::remove_reference<T>::type& param
) {
return param;
}
};
template <typename T>
struct DerefIFN<T*> {
static T& deref (T* param) { return *param; }
};
//Add specialisations for std::unique_ptr & co?
} //namespace wren::detail

View file

@ -1,97 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "wrenpp/handle.hpp"
#include <utility>
namespace wren {
class VM;
//This is meant to be a short lived object representing a still-in-a-slot
//foreign object. Upon casting it to ForeignObject it will create a handle to
//the data in given slot
template <typename T>
class TempForeignObject {
public:
TempForeignObject (VM* vm, T* object, int slot_num) :
m_vm(vm),
m_data(object),
m_slot_num(slot_num)
{ }
VM* vm() const { return m_vm; }
T* data() const { return m_data; }
int slot_num() const { return m_slot_num; }
private:
VM* m_vm;
T* m_data;
int m_slot_num;
};
template <typename T>
class ForeignObject {
public:
ForeignObject() = default;
ForeignObject (std::nullptr_t) : ForeignObject() {}
ForeignObject (T* obj, Handle&& handle);
ForeignObject (ForeignObject&&) = default;
ForeignObject (const TempForeignObject<T>& temp_object);
~ForeignObject() noexcept = default;
ForeignObject& operator= (ForeignObject&&) = default;
bool operator!= (std::nullptr_t) const { return nullptr != m_object; }
bool operator== (std::nullptr_t) const { return nullptr == m_object; }
void set_to_slot (int num);
T& object() { return *m_object; }
const T& object() const { return *m_object; }
Handle& handle() { return m_handle; }
const Handle& handle() const { return m_handle; }
bool is_valid() const { return nullptr != m_object; }
operator T&() { return object(); }
operator const T&() const { return object(); }
operator Handle&() { return handle(); }
operator const Handle&() const { return handle(); }
private:
Handle m_handle;
T* m_object{nullptr};
};
template <typename T>
inline ForeignObject<T>::ForeignObject (T* obj, Handle&& handle) :
m_handle(std::move(handle)),
m_object(obj)
{ }
template <typename T>
inline ForeignObject<T>::ForeignObject (const TempForeignObject<T>& temp_object) :
m_handle(temp_object.vm(), temp_object.slot_num()),
m_object(temp_object.data())
{ }
template <typename T>
inline void ForeignObject<T>::set_to_slot (int num) {
m_handle.set_to_slot(num);
}
} //namespace wren

View file

@ -1,82 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "string_bt.hpp"
#include <cstddef>
#include <utility>
namespace wren {
namespace detail {
consteval std::size_t find_last (const char* str, std::size_t len, char c) {
for (std::size_t z = len; z > 0; --z) {
if (str[z - 1] == c)
return z - 1;
}
return len;
}
consteval std::size_t find_token_end (const char* str, std::size_t len) {
for (std::size_t z = 0; z < len; ++z) {
const bool is_lower = str[z] >= 'a' and str[z] <= 'z';
const bool is_upper = str[z] >= 'A' and str[z] <= 'Z';
const bool is_num = str[z] >= '0' and str[z] <= '9';
const bool is_special = str[z] == '_' or str[z] == ':';
if (not (is_lower or is_upper or is_num or is_special))
return z;
}
return len;
}
template <typename T>
consteval auto guess_class_name_impl() {
#if defined(__GNUC__)
constexpr auto fname = __PRETTY_FUNCTION__;
constexpr auto fname_len = sizeof(__PRETTY_FUNCTION__) / sizeof(__PRETTY_FUNCTION__[0]) - 1;
static_assert(fname_len > 0);
# if defined(__clang__)
//clang: void figure_out_name() [T = MyTest]
# else
//gcc: void figure_out_name() [with T = MyTest]
# endif
constexpr auto last_colon = detail::find_last(fname, fname_len, ':');
constexpr auto last_space = detail::find_last(fname, fname_len, ' ');
constexpr auto last_whatever = (last_colon == fname_len ? last_space : last_colon);
constexpr auto from = last_whatever + (last_whatever == fname_len ? 0 : 1);
constexpr auto len = detail::find_token_end(fname + from, fname_len - from);
constexpr dhandy::bt::string<len+1> retval{fname + from, 0};
return retval;
//#elif defined(_MSC_VER)
//void __cdecl guess_class_name<class MyTest>(void)
//__FUNCSIG__
#else
# error "Unsupported compiler"
#endif
}
} //namespace detail
template <typename T, std::size_t S=detail::guess_class_name_impl<T>().size()>
constexpr dhandy::bt::string g_guessed_class_name = {detail::guess_class_name_impl<T>()};
template <typename T>
constexpr const char* guess_class_name() {
return g_guessed_class_name<T>.data();
}
} //namespace wren

View file

@ -1,41 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "deref_ifn.hpp"
namespace wren::detail {
template <typename T, typename TRaw>
struct IsKindOfHandleHelper {
static constexpr bool value = false;
};
template <typename TRaw>
struct IsKindOfHandleHelper<Handle, TRaw> {
static constexpr bool value = true;
static void set_to_slot (int slot_num, TRaw obj) {DerefIFN<TRaw>::deref(obj).set_to_slot(slot_num);}
};
template <typename U, typename TRaw>
struct IsKindOfHandleHelper<ForeignObject<U>, TRaw> {
static constexpr bool value = true;
static void set_to_slot (int slot_num, TRaw obj) {DerefIFN<TRaw>::deref(obj).set_to_slot(slot_num);}
};
template <typename T>
using IsKindOfHandle = IsKindOfHandleHelper<typename std::remove_pointer<typename std::remove_cvref<T>::type>::type, T>;
} //namespace wren::detail

View file

@ -1,18 +0,0 @@
include_files = [
'construct_foreign_class.hpp',
'crc32.hpp',
'error_type.hpp',
'guess_class_name.hpp',
'has_method.hpp',
'module_and_name.hpp',
'setters_getters.hpp',
'string_bt.hpp',
'strings_in_vector.hpp',
'type_id.hpp',
'wren_class_name_from_type.hpp',
'wren_types.hpp',
]
if not meson.is_subproject()
install_headers(include_files)
endif

View file

@ -1,168 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "string_bt.hpp"
#include "crc32.hpp"
#include <string_view>
#include <cstdint>
#include <cassert>
#include <type_traits>
namespace wren {
typedef decltype(crc32c(nullptr, 0)) ModuleAndNameHashType;
class ModuleAndName;
namespace detail {
template <dhandy::bt::string Str>
struct ModuleAndNameStaticStorage {
static constexpr dhandy::bt::string value = Str;
};
[[gnu::const]]
bool deep_equal (const ModuleAndName& a, const ModuleAndName& b) noexcept;
} //unnamed namespace
//Non-owning, lightweight class for storing a module name + generic name
//pair. It holds a hash value too, which is currently only meaningful for
//module name/class name pairs that are mapped to a c++ class.
//Names are stored as consecutive strings within a single buffer with a
//null-char in-between and at the end so that each name is null-terminated
//and can be used with C APIs.
//Keep the size small, ideally within 2 registers size. Altering this might
//require changes to the assembly source files for DynafuncMaker.
//When passed as a parameter by value, objects of ModuleAndName fit into
//2 registers on 64 bit architectures. This is important because objects
//of this class get hardcoded in the dynamic functions that DynafuncMaker
//spits out.
class ModuleAndName {
friend bool detail::deep_equal(const ModuleAndName&, const ModuleAndName&) noexcept;
template <dhandy::bt::string S1, dhandy::bt::string S2>
friend consteval ModuleAndName make_module_and_name() noexcept;
public:
constexpr ModuleAndName();
constexpr ModuleAndName (const char* base, std::size_t mod_name_len, std::size_t class_name_len);
constexpr bool operator==(const ModuleAndName& other) const noexcept;
constexpr bool operator!=(const ModuleAndName& other) const noexcept;
constexpr bool deep_equal(const ModuleAndName& other) const noexcept;
constexpr const char* module_name_char() const noexcept { return m_base; }
constexpr const char* class_name_char() const noexcept { return m_base + 1 + m_mod_name_len; }
constexpr std::size_t module_name_len() const noexcept { return m_mod_name_len; }
constexpr std::size_t class_name_len() const noexcept { return m_class_name_len; }
constexpr std::string_view module_name() const noexcept { return {module_name_char(), m_mod_name_len}; }
constexpr std::string_view class_name() const noexcept { return {class_name_char(), m_class_name_len}; }
constexpr const char* buffer_address() const noexcept { return m_base; }
private:
constexpr ModuleAndName (const char* base, ModuleAndNameHashType hash, std::size_t mod_name_len, std::size_t class_name_len);
constexpr std::size_t raw_buffer_size() const noexcept;
const char* m_base;
ModuleAndNameHashType m_hash;
std::uint16_t m_mod_name_len;
std::uint16_t m_class_name_len;
static_assert(
sizeof(m_hash) <= sizeof(std::uint32_t),
"Hash type is too large, review this struct or change it back to uint32_t"
);
};
union RawAccessModuleAndName {
constexpr RawAccessModuleAndName (ModuleAndName mn) :
module_and_name(mn)
{ }
ModuleAndName module_and_name;
struct {
void* string;
void* data;
} raw;
static_assert(sizeof(raw) == sizeof(module_and_name));
};
constexpr ModuleAndName::ModuleAndName() :
ModuleAndName(nullptr, 0, 0, 0)
{}
constexpr ModuleAndName::ModuleAndName (const char* base, std::size_t mod_name_len, std::size_t class_name_len) :
ModuleAndName(base, crc32c(base, mod_name_len + class_name_len + 2), mod_name_len, class_name_len)
{}
constexpr ModuleAndName::ModuleAndName (const char* base, ModuleAndNameHashType hash, std::size_t mod_name_len, std::size_t class_name_len) :
m_base(base),
m_hash(hash),
m_mod_name_len(mod_name_len),
m_class_name_len(class_name_len)
{}
constexpr bool ModuleAndName::operator==(const ModuleAndName& other) const noexcept {
const bool retval = (this->m_hash == other.m_hash and deep_equal(other));
return retval;
}
constexpr bool ModuleAndName::operator!=(const ModuleAndName& other) const noexcept {
return not this->operator==(other);
}
constexpr bool ModuleAndName::deep_equal(const ModuleAndName& other) const noexcept {
if (not std::is_constant_evaluated()) {
return detail::deep_equal(*this, other);
}
else {
if (this->raw_buffer_size() != other.raw_buffer_size())
return false;
for (std::size_t z = 0; z < raw_buffer_size(); ++z) {
if (this->m_base[z] != other.m_base[z])
return false;
}
return true;
}
}
constexpr std::size_t ModuleAndName::raw_buffer_size() const noexcept {
return m_mod_name_len + m_class_name_len + 2;
}
template <dhandy::bt::string S1, dhandy::bt::string S2>
consteval ModuleAndName make_module_and_name() noexcept {
using dhandy::bt::string;
using detail::ModuleAndNameStaticStorage;
constexpr string null_char{"\0"};
using StaticStorage = ModuleAndNameStaticStorage<S1 + null_char + S2>;
constexpr const char* data = StaticStorage::value.data();
constexpr std::uint16_t s1_len = static_cast<std::uint16_t>(S1.size());
constexpr std::uint16_t s2_len = static_cast<std::uint16_t>(S2.size());
constexpr ModuleAndNameHashType hash = crc32c(
StaticStorage::value.data(),
StaticStorage::value.size()
);
return ModuleAndName{data, hash, s1_len, s2_len};
}
//short-hand alias for make_module_and_name
template <dhandy::bt::string S1, dhandy::bt::string S2>
constexpr ModuleAndName MN = make_module_and_name<S1, S2>();
} //namespace wren

View file

@ -1,189 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../vm.hpp"
#include "../handle.hpp"
#include "foreign_object.hpp"
#include "module_and_name.hpp"
#include "is_kindof_handle.hpp"
#include <string_view>
#include <vector>
#include <tuple>
namespace wren {
namespace detail {
template <typename T> struct GetTypeToRetType;
template <typename T> using GetTypeToRetType_t = typename GetTypeToRetType<T>::type;
template <typename T> struct TType { typedef T type; };
template<typename T>struct GetTypeToRetType{
static_assert(not std::is_fundamental_v<T>, "User type expected");
static_assert(not std::is_pointer_v<T>, "Unexpected pointer type");
typedef TempForeignObject< std::remove_cv_t<T> > type;
};
template<typename T>struct GetTypeToRetType<ForeignObject<T>> {
//This doesn't make much sense, essentially you're asking wrenpp to
//give you a foreign object by vm/slot when you already have its
//handle
};
template<typename T>struct GetTypeToRetType<TempForeignObject<T>> : TType<TempForeignObject<T>>{};
template<>struct GetTypeToRetType<const char*> : TType<const char*>{};
template<>struct GetTypeToRetType<double> : TType<double>{};
template<>struct GetTypeToRetType<bool> : TType<bool>{};
template<>struct GetTypeToRetType<std::pair<const char*,int>> : TType<std::pair<const char*,int>> {};
template<>struct GetTypeToRetType<int> : TType<int>{};
template<>struct GetTypeToRetType<std::size_t> : TType<std::size_t>{};
template<>struct GetTypeToRetType<std::string> : TType<std::string>{};
template<>struct GetTypeToRetType<std::string_view> : TType<std::string_view>{};
template<>struct GetTypeToRetType<std::vector<char>> : TType<std::vector<char>>{};
#if __cpp_concepts >= 201907
template <typename T>
concept ConstCharTuple =
std::same_as<std::decay_t<T>, Handle> or
std::same_as<std::decay_t<T>, ModuleAndName>;
#endif
#if __cpp_concepts >= 201907
template <typename... Outs, int... Indices, ConstCharTuple... Params>
#else
template <typename... Outs, int... Indices, typename... Params>
#endif
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables_impl (
VM& vm,
std::integer_sequence<int, Indices...>,
Params&&... modules_names
) {
if constexpr (sizeof...(Outs) == 0) {
return {};
}
else {
static_assert(sizeof...(Params) == sizeof...(Outs), "Expected a module/name pair per requested output");
static_assert(sizeof...(Outs) == sizeof...(Indices), "Mismatching index count");
vm.ensure_slots(sizeof...(Params));
(variable(vm, modules_names, Indices), ...);
return std::tuple<detail::GetTypeToRetType_t<Outs>...>(get<Outs>(vm, Indices)...);
}
}
} //namespace detail
void set (VM& vm, int slot_num, const char* value);
void set (VM& vm, int slot_num, double value);
void set (VM& vm, int slot_num, bool value);
void set (VM& vm, int slot_num, std::nullptr_t);
void set (VM& vm, int slot_num, const char* bytes, std::size_t length);
void set (VM& vm, int slot_num, const std::string& value);
void set (VM& vm, int slot_num, std::string_view value);
void set (VM& vm, int slot_num, const std::vector<char>& value);
void set (VM& vm, int slot_num, const char* beg, const char* end);
void set (VM& vm, int slot_num, int value);
void set (VM& vm, int slot_num, std::size_t value);
void set (VM& vm, int slot_num, const Handle& handle);
void set (VM& vm, int slot_num, const ModuleAndName& name);
std::string_view slot_string_view (VM& vm, int slot_num);
template <typename T> detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num);
template <typename T> T* foreign (VM& vm, int slot_num);
#if __cpp_concepts >= 201907
template <typename... Outs, detail::ConstCharTuple... Params>
#else
template <typename... Outs, typename... Params>
#endif
std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names);
inline void set (VM& vm, int slot_num, const char* value) {
vm.set_slot_string(slot_num, value);
}
inline void set (VM& vm, int slot_num, double value) {
vm.set_slot_double(slot_num, value);
}
inline void set (VM& vm, int slot_num, bool value) {
vm.set_slot_bool(slot_num, value);
}
inline void set (VM& vm, int slot_num, std::nullptr_t) {
vm.set_slot_null(slot_num);
}
inline void set (VM& vm, int slot_num, const char* bytes, std::size_t length) {
vm.set_slot_bytes(slot_num, bytes, length);
}
inline void set (VM& vm, int slot_num, const std::string& value) {
vm.set_slot_string(slot_num, value.c_str());
}
inline void set (VM& vm, int slot_num, std::string_view value) {
vm.set_slot_bytes(slot_num, value.data(), value.size());
}
inline void set (VM& vm, int slot_num, const std::vector<char>& value) {
vm.set_slot_bytes(slot_num, value.data(), value.size());
}
inline void set (VM& vm, int slot_num, int value) {
vm.set_slot_double(slot_num, static_cast<double>(value));
}
inline void set (VM& vm, int slot_num, std::size_t value) {
vm.set_slot_double(slot_num, static_cast<double>(value));
}
inline void set (VM& vm, int slot_num, const Handle& handle) {
vm.set_slot_handle(handle, slot_num);
}
inline void set (VM& vm, int slot_num, const ModuleAndName& name) {
vm.variable_or_throw(name.module_name_char(), name.class_name_char(), slot_num);
}
template <typename T>
inline T* foreign (VM& vm, int slot_num) {
T* obj = static_cast<T*>(vm.slot_foreign(slot_num));
return obj;
}
#if __cpp_concepts >= 201907
template <typename... Outs, detail::ConstCharTuple... Params>
#else
template <typename... Outs, typename... Params>
#endif
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names) {
return detail::variables_impl<Outs...>(vm, std::make_integer_sequence<int, sizeof...(Outs)>(), std::forward<Params>(modules_names)...);
}
template <typename T>
inline detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num) {
return {&vm, foreign<T>(vm, slot_num), slot_num};
}
template<> const char* get<const char*> (VM& vm, int slot_num);
template<> double get<double> (VM& vm, int slot_num);
template<> bool get<bool> (VM& vm, int slot_num);
template<> std::pair<const char*, int> get<std::pair<const char*,int>> (VM& vm, int slot_num);
template<> int get<int> (VM& vm, int slot_num);
template<> std::size_t get<std::size_t> (VM& vm, int slot_num);
template<> std::string get<std::string> (VM& vm, int slot_num);
template<> std::string_view get<std::string_view> (VM& vm, int slot_num);
template<> std::vector<char> get<std::vector<char>> (VM& vm, int slot_num);
} //namespace wren

View file

@ -1,157 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <string_view>
#include <utility>
#include <algorithm>
#include <cassert>
namespace wren {
namespace detail {
template <std::size_t Num>
struct StringsInVectorBase;
struct StringsInVectorWordRange {
std::size_t start, length;
};
template <std::size_t Num>
struct StringsInVectorBase {
explicit StringsInVectorBase (StringsInVectorWordRange range) :
m_word_range(range)
{ }
StringsInVectorWordRange m_word_range;
};
template <std::size_t Index, typename String, typename... Strings>
[[gnu::pure]]
std::size_t string_offset_at_index (const String& string, const Strings&... strings) {
static_assert(Index < sizeof...(Strings) + 1, "Index out of range");
if constexpr (not Index) {
return 0;
}
else {
return std::string_view{string}.size() + string_offset_at_index<Index - 1>(strings...);
}
}
inline void set_zero (char& value) {
value = '\0';
}
} //namespace detail
template <std::size_t Count, typename IndexSeq>
class StringsInVectorImplem;
//It's a class that stores a series of strings in a vector, consecutively
//and interleaved by a null char. Objects of this class are safe to move
//and copy, move doesn't invalidate previously obtained string_views
//and strings_views are guaranteed to be null-terminated, so the result
//of data() is safe to pass to C functions.
template <std::size_t Count, std::size_t... Indices>
class StringsInVectorImplem<Count, std::index_sequence<Indices...>> : detail::StringsInVectorBase<Indices>... {
typedef detail::StringsInVectorWordRange WordRange;
template <typename... Strings> friend std::vector<char> strings_to_vector(const Strings&...);
public:
template <typename... Strings>
StringsInVectorImplem (const Strings&... strings);
template <std::size_t Index>
std::string_view as_string_view() const;
bool operator== (const StringsInVectorImplem& other) const;
bool operator< (const StringsInVectorImplem& other) const;
protected:
const char* raw_buffer() const;
std::size_t raw_buffer_size() const;
private:
std::vector<char> m_memory;
};
template <std::size_t Count, std::size_t... Indices>
template <typename... Strings>
inline StringsInVectorImplem<Count, std::index_sequence<Indices...>>::StringsInVectorImplem(const Strings&... strings) :
detail::StringsInVectorBase<Indices>(WordRange{detail::string_offset_at_index<Indices>(strings...) + Indices, std::string_view{strings}.size()})...
{
using detail::string_offset_at_index;
using detail::set_zero;
const std::size_t buffer_size = (std::string_view{strings}.size() + ...) + sizeof...(Indices);
m_memory.resize(buffer_size);
(std::copy(
std::string_view{strings}.cbegin(),
std::string_view{strings}.cend(),
m_memory.begin() + string_offset_at_index<Indices>(strings...) + Indices
), ...);
//zero out the byte after each string
(set_zero(m_memory[string_offset_at_index<Indices>(strings...) + Indices + std::string_view(strings).size()]), ...);
}
template <std::size_t Count, std::size_t... Indices>
template <std::size_t Index>
inline std::string_view StringsInVectorImplem<Count, std::index_sequence<Indices...>>::as_string_view() const {
static_assert(Index < Count, "Index out of range");
const auto& word_range = detail::StringsInVectorBase<Index>::m_word_range;
assert(m_memory.size() >= word_range.start + word_range.length + 1);
std::string_view retval{
m_memory.data() + word_range.start,
word_range.length
};
assert(*(retval.data() + retval.length()) == '\0');
return retval;
}
template <std::size_t Count, std::size_t... Indices>
inline bool StringsInVectorImplem<Count, std::index_sequence<Indices...>>::operator== (const StringsInVectorImplem& other) const {
return this->m_memory == other.m_memory;
}
template <std::size_t Count, std::size_t... Indices>
inline bool StringsInVectorImplem<Count, std::index_sequence<Indices...>>::operator< (const StringsInVectorImplem& other) const {
std::string_view this_memory{m_memory.data(), m_memory.size()};
std::string_view other_memory{other.m_memory.data(), other.m_memory.size()};
return this_memory < other_memory;
}
template <std::size_t Count, std::size_t... Indices>
inline const char* StringsInVectorImplem<Count, std::index_sequence<Indices...>>::raw_buffer() const {
return m_memory.data();
}
template <std::size_t Count, std::size_t... Indices>
inline std::size_t StringsInVectorImplem<Count, std::index_sequence<Indices...>>::raw_buffer_size() const {
return m_memory.size();
}
template <std::size_t Count>
using StringsInVector = StringsInVectorImplem<Count, decltype(std::make_index_sequence<Count>())>;
template <typename... Strings>
inline std::vector<char> strings_to_vector (const Strings&... strings) {
StringsInVector<sizeof...(Strings)> siv{strings...};
return siv.m_memory;
}
} //namespace wren

View file

@ -1,65 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
namespace wren {
//from:
//https://codereview.stackexchange.com/questions/48594/unique-type-id-no-rtti
class TypeID {
using sig = TypeID();
sig* m_id;
constexpr TypeID(sig* id) : m_id{id} {}
public:
template<typename T>
friend constexpr TypeID type_id();
TypeID (const TypeID&) = default;
TypeID (TypeID&&) = default;
~TypeID() noexcept = default;
TypeID& operator= (const TypeID&) = default;
TypeID& operator= (TypeID&&) = default;
constexpr bool operator==(TypeID other) const noexcept;
constexpr bool operator!=(TypeID other) const noexcept;
constexpr bool operator<(TypeID other) const noexcept;
constexpr std::uintptr_t id() const noexcept;
};
template<typename T>
constexpr TypeID type_id() { return &type_id<T>; }
constexpr bool TypeID::operator==(TypeID other) const noexcept {
return id() == other.id();
}
constexpr bool TypeID::operator!=(TypeID other) const noexcept {
return id() != other.id();
}
constexpr bool TypeID::operator<(TypeID other) const noexcept {
return id() < other.id();
}
constexpr std::uintptr_t TypeID::id() const noexcept {
return reinterpret_cast<std::uintptr_t>(m_id);
}
} //namespace wren

View file

@ -1,44 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "module_and_name.hpp"
#include "type_id.hpp"
#include "crc32.hpp"
#include <utility>
#include <string_view>
namespace wren {
class VM;
namespace detail {
//Just an utility function to call a method on the class manager in vm
//and return its return value without including the header for the
//class manager. Useful in inline functions in header files where
//including class_manager.hpp would propagate it everywhere.
ModuleAndName fetch_class_name_from_manager (
const VM& vm,
TypeID hash
);
template <typename T>
inline ModuleAndName wren_class_name_from_type (const VM& vm) {
return fetch_class_name_from_manager(vm, type_id<T>());
}
} //namespace detail
} //namespace wren

View file

@ -1,34 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "module_and_name.hpp"
#include <string_view>
namespace wren {
class VM;
typedef std::string_view wren_string_t;
typedef void(*finalizer_t)(void*);
typedef void(*foreign_method_t)(VM&, ModuleAndName);
struct foreign_class_t {
foreign_method_t allocate;
finalizer_t finalize;
};
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -27,7 +27,6 @@ namespace wren {
Handle() noexcept;
Handle (const Handle&) = delete;
Handle (Handle&& other) noexcept;
Handle (VM* vm, int slot_num);
Handle (VM* vm, WrenHandle* handle) noexcept :
m_handle(handle),
m_vm(vm)
@ -43,8 +42,6 @@ namespace wren {
operator WrenHandle*() const { return m_handle; }
operator bool() const { return nullptr != m_handle; }
void set_to_slot (int num);
private:
WrenHandle* m_handle;
VM* m_vm;

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -66,17 +66,5 @@
}; \
}
#define define_has_typedef(typedef_name,pretty_name) \
template <typename T> \
struct Has ## pretty_name ## Typedef { \
private: \
struct TrueType { int a[2]; }; \
typedef int FalseType; \
template <typename C> static TrueType has_typedef ( const typename C::typedef_name* ); \
template <typename C> static FalseType has_typedef ( ... ); \
public: \
enum { value = sizeof(has_typedef<T>(nullptr)) == sizeof(TrueType) }; \
}
namespace wren {
} //namespace wren

View file

@ -1,15 +0,0 @@
include_files = [
'callback_manager.hpp',
'class_manager.hpp',
'configuration.hpp',
'def_configuration.hpp',
'handle.hpp',
'vm_fun.hpp',
'vm.hpp',
]
if not meson.is_subproject()
install_headers(include_files)
endif
subdir('detail')

View file

@ -18,13 +18,9 @@
#ifndef id170B0E6C34D14EBA9B92A35977BDBFB3
#define id170B0E6C34D14EBA9B92A35977BDBFB3
//#define PRINTABLE_STRING_BT
#include <utility>
#include <cstddef>
#if defined(PRINTABLE_STRING_BT)
# include <iostream>
#endif
#include <iostream>
#include <stdexcept>
namespace dhandy {
@ -32,10 +28,8 @@ namespace dhandy {
template <std::size_t S, typename Ch=char>
class string;
#if defined(PRINTABLE_STRING_BT)
template <std::size_t S, typename Ch>
std::basic_ostream<Ch>& operator<< ( std::basic_ostream<Ch>& parStream, const string<S, Ch>& parString );
#endif
namespace implem {
template <std::size_t S, typename Ch> constexpr bool eq (const string<S, Ch>& l, const string<S, Ch>& r);
@ -43,17 +37,11 @@ namespace dhandy {
template <std::size_t S, typename Ch>
class string {
#if defined(PRINTABLE_STRING_BT)
friend std::ostream& operator<< <>( std::ostream& parStream, const string<S>& parString );
#endif
friend constexpr bool implem::eq<S, Ch> (const string<S, Ch>&, const string<S, Ch>&);
public:
using value_type = Ch;
constexpr string ( const string& other ) = default;
constexpr string ( const value_type (&parString)[S] );
//overload for pointers, int is only for overload disambiguation
constexpr string ( const value_type* parString, int );
constexpr string ( const value_type* parString );
constexpr std::size_t size ( void ) const { return S - 1; }
template <std::size_t S2>
@ -64,26 +52,18 @@ namespace dhandy {
template <std::size_t S2> constexpr bool operator== (const string<S2, Ch>&) const { return false; }
template <typename... Args>
requires (std::is_same_v<Args, Ch> && ...)
constexpr string ( Args... );
constexpr const value_type (&data_arr() const)[S] { return m_data; }
constexpr const value_type* data() const { return m_data; }
//can't have any private members but from below this point please
//consider everything as private
//private:
private:
template <std::size_t... I>
constexpr string ( std::index_sequence<I...>, const value_type* parString );
const value_type m_data[S];
};
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
namespace implem {
template <std::size_t S, std::size_t S2, std::size_t... I>
constexpr string<S + S2 - 1> concat ( std::index_sequence<I...>, const string<S>& parLeft, const string<S2>& parRight ) {
@ -105,21 +85,14 @@ namespace dhandy {
}
template <std::size_t S, typename Ch>
inline constexpr string<S, Ch>::string (const value_type (&parString)[S]) :
string(std::make_index_sequence<S>(), parString)
{
}
template <std::size_t S, typename Ch>
inline constexpr string<S, Ch>::string (const value_type* parString, int) :
inline constexpr string<S, Ch>::string (const value_type* parString) :
string(std::make_index_sequence<S>(), parString)
{
}
template <std::size_t S, typename Ch>
template <typename... Args>
requires (std::is_same_v<Args, Ch> && ...)
constexpr inline string<S, Ch>::string (Args... parArgs) :
inline constexpr string<S, Ch>::string (Args... parArgs) :
m_data{parArgs...}
{
}
@ -130,13 +103,21 @@ namespace dhandy {
return implem::concat(std::make_index_sequence<S + S2 - 1>(), string<S>(m_data), parOther);
}
#if defined(PRINTABLE_STRING_BT)
template <std::size_t S, typename Ch>
inline std::ostream& operator<< (std::ostream& parStream, const string<S, Ch>& parString) {
parStream << parString.m_data;
return parStream;
}
#endif
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
template <std::size_t S, typename Ch>
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
return string<S>(parData);
}
template <std::size_t S, typename Ch>
constexpr bool string<S, Ch>::operator== (const string<S, Ch>& other) const {
@ -146,7 +127,7 @@ namespace dhandy {
template <std::size_t S, typename Ch>
template <std::size_t Start, std::size_t Len>
constexpr auto string<S, Ch>::substr() const {
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1), 0) + string<1, Ch>({Ch{}});
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1)) + make_string("");
}
} //namespace bt
} //namespace dhandy

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,11 +17,10 @@
#pragma once
#include "detail/has_method.hpp"
#include "detail/error_type.hpp"
#include "detail/type_id.hpp"
#include "detail/wren_types.hpp"
#include "has_method.hpp"
#include "error_type.hpp"
#include "handle.hpp"
#include "StringCRC32.hpp"
#include <memory>
#include <tuple>
#include <utility>
@ -35,23 +34,28 @@ namespace wren {
class Configuration;
class VM;
class DynafuncMaker;
class CallbackManager;
class ClassManager;
typedef void(*foreign_method_t)(VM&);
typedef void(*finalizer_t)(void*);
struct foreign_class_t {
foreign_method_t allocate;
finalizer_t finalize;
};
enum class SlotType {
Bool, Num, Foreign, List, Null, String, Unknown, Map
Bool, Num, Foreign, List, Null, String, Unknown
};
namespace detail {
struct Callbacks {
void (*write_fn)(Configuration&, VM*, wren_string_t) {nullptr};
void (*error_fn)(Configuration&, VM*, ErrorType, wren_string_t, int, wren_string_t) {nullptr};
void (*write_fn)(Configuration&, VM*, const char*) {nullptr};
void (*error_fn)(Configuration&, VM*, ErrorType, const char*, int, const char*) {nullptr};
void* (*reallocate_fn)(void*, std::size_t) {nullptr};
const char* (*resolve_module_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
char* (*load_module_fn)(Configuration&, VM*, wren_string_t) {nullptr};
foreign_method_t (*foreign_method_fn)(Configuration&, VM*, wren_string_t, wren_string_t, bool, wren_string_t) {nullptr};
foreign_class_t (*foreign_class_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
void (*load_module_complete_fn)(Configuration&, VM*, wren_string_t, char*) {nullptr};
const char* (*resolve_module_fn)(Configuration&, VM*, const char*, const char*) {nullptr};
char* (*load_module_fn)(Configuration&, VM*, const char*) {nullptr};
foreign_method_t (*foreign_method_fn)(Configuration&, VM*, const char*, const char*, bool, const char*) {nullptr};
foreign_class_t (*foreign_class_fn)(Configuration&, VM*, const char*, const char*) {nullptr};
Configuration* config_obj {nullptr};
VM* owner {nullptr};
@ -74,8 +78,7 @@ namespace wren {
void release_handle (Handle& handle) noexcept;
void ensure_slots(int num_slots);
int slot_count();
void variable(const char* module, const char* name, int slot) noexcept;
void variable_or_throw(const char* module, const char* name, int slot);
void variable(const char* module, const char* name, int slot);
void set_slot_handle(const Handle& handle, int slot);
SlotType slot_type(int slot_num);
Handle slot_handle(int slot_num);
@ -99,42 +102,32 @@ namespace wren {
template <typename U> U* user_data();
template <typename U> void set_user_data (U* user_data);
void set_user_data (std::nullptr_t);
bool has_user_data() const noexcept;
bool has_module (const char* module) const noexcept;
bool has_variable (const char* module, const char* name) const noexcept;
void abort_fiber(int slot_num);
bool has_user_data() const;
std::size_t dynafunc_byte_size() const;
void reset (Configuration* conf);
CallbackManager& callback_manager();
const CallbackManager& callback_manager() const;
ClassManager& class_manager();
const ClassManager& class_manager() const;
private:
struct LocalData;
VM (Configuration* conf, const detail::Callbacks&, void* user_data, TypeID user_data_type);
VM (Configuration* conf, const detail::Callbacks&, void* user_data, std::uint32_t user_data_type);
DynafuncMaker* dynafunc_maker();
TypeID user_data_type() const;
std::uint32_t user_data_type() const;
void* void_user_data();
void set_user_data (void* user_data, TypeID user_data_type);
void set_user_data (void* user_data, std::uint32_t user_data_type);
template <typename T> detail::Callbacks to_callbacks (T& conf);
std::unique_ptr<LocalData> m_local;
};
namespace detail {
define_method_info(write_fn, write, void, VM*, wren_string_t);
define_method_info(error_fn, error, void, VM*, ErrorType, wren_string_t, int, wren_string_t);
define_method_info(write_fn, write, void, VM*, const char*);
define_method_info(error_fn, error, void, VM*, ErrorType, const char*, int, const char*);
define_method_info(reallocate_fn, reallocate, void*, void*, std::size_t);
define_method_info(resolve_module_fn, resolve_module, wren_string_t, wren_string_t, wren_string_t);
define_method_info(load_module_fn, load_module, char*, VM*, wren_string_t);
define_method_info(foreign_method_fn, foreign_method, foreign_method_t, VM*, wren_string_t, wren_string_t, bool, wren_string_t);
define_method_info(foreign_class_fn, foreign_class, foreign_class_t, VM*, wren_string_t, wren_string_t);
define_method_info(load_module_complete_fn, load_module_complete, void, VM*, wren_string_t, char*);
define_method_info(resolve_module_fn, resolve_module, const char*, const char*, const char*);
define_method_info(load_module_fn, load_module, char*, VM*, const char*);
define_method_info(foreign_method_fn, foreign_method, foreign_method_t, VM*, const char*, const char*, bool, const char*);
define_method_info(foreign_class_fn, foreign_class, foreign_class_t, VM*, const char*, const char*);
template <typename T, typename F> struct AnyFunctionWrap;
template <typename T, typename R, typename... Args>
@ -151,6 +144,12 @@ namespace wren {
return (*M)(args...);
}
};
template <typename U>
[[gnu::const]]
inline constexpr std::uint32_t type_id() {
return duckcore::StringCRC32(__PRETTY_FUNCTION__);
}
} //namespace detail
template <typename T>
@ -184,15 +183,12 @@ namespace wren {
if constexpr (detail::method_foreign_class::exists<T>::value)
ret.foreign_class_fn = &detail::AnyFunctionWrap<T, decltype(&T::foreign_class_fn)>::template call<&T::foreign_class_fn>;
if constexpr (detail::method_load_module_complete::exists<T>::value)
ret.load_module_complete_fn = &detail::AnyFunctionWrap<T, decltype(&T::load_module_complete_fn)>::template call<&T::load_module_complete_fn>;
return ret;
}
template <typename U>
inline U* VM::user_data() {
if (user_data_type() != type_id<U>()) {
if (user_data_type() != detail::type_id<U>()) {
throw std::runtime_error("Wrong user data type requested");
}
return reinterpret_cast<U*>(void_user_data());
@ -200,7 +196,7 @@ namespace wren {
template <typename U>
inline void VM::set_user_data (U* user_data) {
set_user_data(reinterpret_cast<void*>(user_data), type_id<U>());
set_user_data(reinterpret_cast<void*>(user_data), detail::type_id<U>());
}
template <typename T>
@ -209,7 +205,7 @@ namespace wren {
static_cast<Configuration*>(conf),
to_callbacks(*conf),
nullptr,
type_id<std::nullptr_t>()
detail::type_id<std::nullptr_t>()
)
{
}
@ -220,7 +216,7 @@ namespace wren {
static_cast<Configuration*>(conf),
to_callbacks(*conf),
reinterpret_cast<void*>(user_data),
type_id<U>()
detail::type_id<U>()
)
{
}

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -18,165 +18,234 @@
#pragma once
#include "vm.hpp"
#include "detail/string_bt.hpp"
#if defined(WRENPP_WITH_NAME_GUESSING)
# include "detail/guess_class_name.hpp"
#endif
#include "detail/wren_types.hpp"
#include "detail/construct_foreign_class.hpp"
#include "detail/setters_getters.hpp"
#include "detail/wren_class_name_from_type.hpp"
#include "detail/is_kindof_handle.hpp"
#include "detail/foreign_object.hpp"
#include "string_bt.hpp"
#include <string>
#include <string_view>
#include <vector>
#include <type_traits>
#include <cstddef>
#include <utility>
namespace wren {
typedef std::tuple<const char*, const char*> ModuleAndName;
namespace detail {
template <typename T> struct GetTypeToRetType;
template <typename T> using GetTypeToRetType_t = typename GetTypeToRetType<T>::type;
#if __cpp_concepts >= 201907
template <typename T>
concept ConstCharTuple = requires {
std::same_as<std::remove_cv_t<T>, Handle> or
std::same_as<std::remove_cv_t<T>, ModuleAndName>;
};
#endif
} //namespace detail
#if __cpp_concepts >= 201907
template <typename... Outs, detail::ConstCharTuple... Params>
#else
template <typename... Outs, typename... Params>
#endif
std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names);
template <typename R, typename... Args>
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
template <typename R, typename... Args>
R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args);
R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args);
template <typename R, std::size_t N, typename... Args>
R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args);
template <typename R, std::size_t N, typename... Args>
R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args);
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
template <typename T, typename... Args>
ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
template <typename T>
foreign_class_t make_foreign_class();
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, dhandy::bt::string Mod, typename... Args>
ForeignObject<T> make_wren_object(VM& vm, Args&&... args);
#endif
template <auto V>
foreign_method_t make_method_bindable();
void interpret (VM& vm, const std::string& module_name, const std::string& script);
void variable(VM& vm, ModuleAndName mod_and_name, int slot);
void set (VM& vm, int slot_num, const char* value);
void set (VM& vm, int slot_num, double value);
void set (VM& vm, int slot_num, bool value);
void set (VM& vm, int slot_num, std::nullptr_t);
void set (VM& vm, int slot_num, const char* bytes, std::size_t length);
void set (VM& vm, int slot_num, const std::string& value);
void set (VM& vm, int slot_num, std::string_view value);
void set (VM& vm, int slot_num, const std::vector<char>& value);
void set (VM& vm, int slot_num, const char* beg, const char* end);
void set (VM& vm, int slot_num, int value);
void set (VM& vm, int slot_num, std::size_t value);
std::string_view slot_string_view (VM& vm, int slot_num);
template <typename T> detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num);
template <typename T> 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);
void variable_ensure_slot(VM& vm, ModuleAndName mod_and_name, int slot);
void variable_ensure_slot(VM& vm, const Handle& handle, int slot);
void abort_fiber_with_error (VM& vm, int slot, std::string_view message);
namespace detail {
template <typename T>
struct CleanParamForGet { typedef typename std::decay<T>::type type; };
template <typename T>
struct CleanParamForGet<ForeignObject<T>> { typedef T type; };
template <typename T>
using CleanParamForGetT = typename CleanParamForGet<T>::type;
template <typename T> struct TType { typedef T type; };
template<typename T>struct GetTypeToRetType{
static_assert(not std::is_fundamental_v<T>, "User type expected");
static_assert(not std::is_pointer_v<T>, "Unexpected pointer type");
typedef std::remove_cv_t<T>* type;
};
template<>struct GetTypeToRetType<const char*> : TType<const char*>{};
template<>struct GetTypeToRetType<double> : TType<double>{};
template<>struct GetTypeToRetType<bool> : TType<bool>{};
template<>struct GetTypeToRetType<std::pair<const char*,int>> : TType<std::pair<const char*,int>> {};
template<>struct GetTypeToRetType<int> : TType<int>{};
template<>struct GetTypeToRetType<std::size_t> : TType<std::size_t>{};
template<>struct GetTypeToRetType<std::string> : TType<std::string>{};
template<>struct GetTypeToRetType<std::string_view> : TType<std::string_view>{};
template<>struct GetTypeToRetType<std::vector<char>> : TType<std::vector<char>>{};
#if __cpp_concepts >= 201907
template <typename... Outs, int... Indices, ConstCharTuple... Params>
#else
template <typename... Outs, int... Indices, typename... Params>
#endif
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables_impl (
VM& vm,
std::integer_sequence<int, Indices...>,
Params&&... modules_names
) {
if constexpr (sizeof...(Outs) == 0) {
return {};
}
else {
static_assert(sizeof...(Params) == sizeof...(Outs), "Expected a module/name pair per requested output");
static_assert(sizeof...(Outs) == sizeof...(Indices), "Mismatching index count");
vm.ensure_slots(sizeof...(Params));
(variable(vm, modules_names, Indices), ...);
return std::tuple<detail::GetTypeToRetType_t<Outs>...>(get<Outs>(vm, Indices)...);
}
}
template <typename T>
inline void set_single_for_call (VM& vm, int slot, const T& value) {
set(vm, slot, value);
}
template <>
inline void set_single_for_call (VM& vm, int slot_num, const Handle& handle) {
vm.set_slot_handle(handle, slot_num);
}
template <>
inline void set_single_for_call (VM& vm, int slot_num, const ModuleAndName& name) {
variable(vm, name, slot_num);
}
//Sets arguments so wren is ready to perform a function call. It doesn't
//touch at slot 0, so eventual objects for method calls must be set
//manually
template <typename... Args, int... Indices>
inline void set_for_call (std::integer_sequence<int, Indices...>, VM& vm, const Args&... args) {
vm.ensure_slots(sizeof...(Args));
(set(vm, Indices + 1, args), ...);
(set_single_for_call(vm, Indices + 1, args), ...);
}
template <auto V>
class CallImplemProvider;
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)>
class CallImplemProvider<Method> {
protected:
typedef R return_type;
static constexpr std::size_t argument_count = sizeof...(Args);
template <typename T, typename R, auto Method, typename... Args> struct MakeMethodBindableConstNonConst {
private:
template <int... Indices>
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
T* const obj = foreign<T>(vm, 0);
return (obj->*Method)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
T* obj = foreign<T>(vm, 0);
return (obj->*Method)(get<std::decay_t<Args>>(vm, Indices + 1)...);
}
};
template <typename T, typename R, typename... Args, R(T::*ConstMethod)(Args...)const>
class CallImplemProvider<ConstMethod> {
protected:
typedef R return_type;
static constexpr std::size_t argument_count = sizeof...(Args);
template <int... Indices>
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
T* const obj = foreign<T>(vm, 0);
return (obj->*ConstMethod)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
}
};
template <typename R, typename... Args, R(*Function)(Args...)>
class CallImplemProvider<Function> {
protected:
typedef R return_type;
static constexpr std::size_t argument_count = sizeof...(Args);
template <int... Indices>
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
return (*Function)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
}
};
template <auto V>
struct MakeFunctionBindable : private CallImplemProvider<V> {
foreign_method_t operator()() const {
using R = typename CallImplemProvider<V>::return_type;
constexpr int argument_count = static_cast<int>(CallImplemProvider<V>::argument_count);
return [](VM& vm, ModuleAndName mn) {
public:
static foreign_method_t make() {
return [](VM& vm) {
if constexpr (std::is_same_v<R, void>) {
CallImplemProvider<V>::call_implem(std::make_integer_sequence<int, argument_count>(), vm);
call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
}
else {
auto ret = CallImplemProvider<V>::call_implem(std::make_integer_sequence<int, argument_count>(), vm);
//TODO: check for errors
assert(vm.slot_count() >= 1); //vm.ensure_slots(1);
if constexpr (std::is_fundamental<R>::value) {
set(vm, 0, ret);
}
else if constexpr (IsKindOfHandle<R>::value) {
IsKindOfHandle<R>::set_to_slot(0, ret);
assert(vm.slot_type(0) == SlotType::Foreign);
}
else {
ModuleAndName wren_name = wren_class_name_from_type<R>(vm);
ForeignObject<R> new_object = make_wren_object<R>(vm, wren_name, std::move(ret));
static_cast<void>(new_object);
}
auto ret = call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
vm.ensure_slots(1);
set(vm, 0, ret);
}
};
}
};
template <typename T, void(T::*Method)(VM&,ModuleAndName)> struct MakeFunctionBindable<Method> {
foreign_method_t operator()() const {
return [](VM& vm, ModuleAndName mn) {
template <auto V> struct MakeMethodBindable;
template <typename T, void(T::*Method)(VM&)> struct MakeMethodBindable<Method> {
static foreign_method_t make() {
return [](VM& vm) {
T* obj = foreign<T>(vm, 0);
(obj->*Method)(vm, mn);
(obj->*Method)(vm);
};
}
};
template <void(*Function)(VM&,ModuleAndName)> struct MakeFunctionBindable<Function> {
foreign_method_t operator()() const {
return [](VM& vm, ModuleAndName mn) {
(*Function)(vm, mn);
};
}
};
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)> struct MakeMethodBindable<Method> : MakeMethodBindableConstNonConst<T, R, Method, Args...> {};
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)const> struct MakeMethodBindable<Method> : MakeMethodBindableConstNonConst<T, R, Method, Args...> {};
} //namespace detail
#if __cpp_concepts >= 201907
template <typename... Outs, detail::ConstCharTuple... Params>
#else
template <typename... Outs, typename... Params>
#endif
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names) {
return detail::variables_impl<Outs...>(vm, std::make_integer_sequence<int, sizeof...(Outs)>(), std::forward<Params>(modules_names)...);
}
inline void interpret (VM& vm, const std::string& module_name, const std::string& script) {
return vm.interpret(module_name.c_str(), script.c_str());
}
inline void set (VM& vm, int slot_num, const char* value) {
vm.set_slot_string(slot_num, value);
}
inline void set (VM& vm, int slot_num, double value) {
vm.set_slot_double(slot_num, value);
}
inline void set (VM& vm, int slot_num, bool value) {
vm.set_slot_bool(slot_num, value);
}
inline void set (VM& vm, int slot_num, std::nullptr_t) {
vm.set_slot_null(slot_num);
}
inline void set (VM& vm, int slot_num, const char* bytes, std::size_t length) {
vm.set_slot_bytes(slot_num, bytes, length);
}
inline void set (VM& vm, int slot_num, const std::string& value) {
vm.set_slot_string(slot_num, value.c_str());
}
inline void set (VM& vm, int slot_num, std::string_view value) {
vm.set_slot_bytes(slot_num, value.data(), value.size());
}
inline void set (VM& vm, int slot_num, const std::vector<char>& value) {
vm.set_slot_bytes(slot_num, value.data(), value.size());
}
inline void set (VM& vm, int slot_num, int value) {
vm.set_slot_double(slot_num, static_cast<double>(value));
}
inline void set (VM& vm, int slot_num, std::size_t value) {
vm.set_slot_double(slot_num, static_cast<double>(value));
}
template <typename T>
inline T* foreign (VM& vm, int slot_num) {
T* obj = static_cast<T*>(vm.slot_foreign(slot_num));
return obj;
}
template <typename R, typename... Args>
inline R call (VM& vm, const Handle& object, const Handle& method, const Args&... args) {
detail::set_for_call<Args...>(std::make_integer_sequence<int, sizeof...(Args)>(), vm, args...);
vm.set_slot_handle(object, 0);
vm.call(method);
if constexpr (not std::is_same<void, R>::value) {
return get<R>(vm, 0);
@ -184,7 +253,7 @@ namespace wren {
}
template <typename R, typename... Args>
inline R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args) {
inline R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args) {
vm.ensure_slots(sizeof...(args) + 1);
variable(vm, object, 0);
Handle obj_handle = vm.slot_handle(0);
@ -193,51 +262,58 @@ namespace wren {
template <typename R, std::size_t N, typename... Args>
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
using dhandy::bt::string;
const constexpr auto params = string("(") +
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
string(")");
const constexpr char dummy_name_buff[N] = {0};
const constexpr auto params = dhandy::bt::string<N, char>(dummy_name_buff) +
dhandy::bt::make_string("(") +
((static_cast<void>(args), dhandy::bt::make_string(",_")) + ... + dhandy::bt::make_string("")).template substr<1>() +
dhandy::bt::make_string(")");
;
char cat_buff[params.size() + 1 + N - 1];
char cat_buff[params.size() + 1];
std::copy(method, method + N - 1, cat_buff);
std::copy(params.data(), params.data() + params.size() + 1, cat_buff + N - 1);
std::copy(params.data() + N - 1, params.data() + params.size() + 1, cat_buff + N - 1);
return call<R, Args...>(vm, object, vm.make_call_handle(cat_buff), args...);
}
template <typename R, std::size_t N, typename... Args>
inline R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args) {
inline R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args) {
vm.ensure_slots(sizeof...(args) + 1);
variable(vm, object, 0);
Handle obj_handle = vm.slot_handle(0);
return call<R, N, Args...>(vm, obj_handle, method, args...);
}
template <typename T, typename... Args>
inline ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable_ensure_slot(vm, mn, 0);
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
try {
T* const obj = new(mem) T{std::forward<Args>(args)...};
return {obj, vm.slot_handle(0)};
}
catch (const std::runtime_error& err) {
abort_fiber_with_error(vm, 1, err.what());
return nullptr;
}
}
template <typename T>
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<T*>(mem);
cale->~T();
};
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, dhandy::bt::string Mod, typename... Args>
inline ForeignObject<T> make_wren_object(VM& vm, Args&&... args) {
return make_wren_object<T>(
vm,
MN<Mod, g_guessed_class_name<T>>,
std::forward<Args>(args)...
);
return ret;
}
#endif
template <auto V>
constexpr detail::MakeFunctionBindable<V> make_function_bindable;
inline foreign_method_t make_method_bindable() {
return detail::MakeMethodBindable<V>::make();
}
template <typename T>
inline detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num) {
return foreign<T>(vm, slot_num);
}
template<> const char* get<const char*> (VM& vm, int slot_num);
template <> double get<double> (VM& vm, int slot_num);
template <> bool get<bool> (VM& vm, int slot_num);
template <> std::pair<const char*, int> get<std::pair<const char*,int>> (VM& vm, int slot_num);
template<> int get<int> (VM& vm, int slot_num);
template<> std::size_t get<std::size_t> (VM& vm, int slot_num);
template<> std::string get<std::string> (VM& vm, int slot_num);
template <> std::string_view get<std::string_view> (VM& vm, int slot_num);
template <> std::vector<char> get<std::vector<char>> (VM& vm, int slot_num);
} //namespace wren

8
links.txt Normal file
View file

@ -0,0 +1,8 @@
https://stackoverflow.com/questions/36093158/how-does-string-conversion-between-pyunicode-string-and-c-string-work
https://stackoverflow.com/questions/8001923/python-extension-module-with-variable-number-of-arguments
https://stackoverflow.com/questions/27451743/how-can-i-print-the-type-of-a-pyobject-in-an-error-message-for-an-embedded-pytho/27452057
https://docs.python.org/3.8/c-api/unicode.html#creating-and-accessing-unicode-strings
https://docs.python.org/3/extending/extending.html
https://stackoverflow.com/questions/28263177/should-tp-alloc-tp-dealloc-and-tp-new-tp-free-be-considered-as-pairs

View file

@ -1,9 +1,11 @@
project('wrenpp', 'cpp',
version: '0.2.0',
meson_version: '>=0.55.0',
default_options: ['buildtype=release', 'cpp_std=c++20', 'b_ndebug=if-release']
version: '0.1.1',
meson_version: '>=0.49.2',
default_options: ['buildtype=release', 'cpp_std=c++17', 'b_ndebug=if-release'],
)
pymod = import('python')
wren_dep = dependency('wren', version: '>=0.2.0',
fallback: ['wren', 'wren_dep'],
default_options: [
@ -14,7 +16,11 @@ wren_dep = dependency('wren', version: '>=0.2.0',
],
static: true,
)
public_incl = [include_directories('include')]
python = pymod.find_installation('python3',
required: get_option('wrenpp_with_python'),
disabler: true
)
public_incl = include_directories('include')
os = host_machine.system()
if os == 'gnu'
@ -35,22 +41,49 @@ conf = configuration_data()
if os == 'gnu' and arch == 'amd64'
ptr_size = 8
func_ptr_size = 8
elif os == 'gnu' and arch == 'aarch64'
ptr_size = 8
func_ptr_size = 8
endif
global_compiler_opts = []
if get_option('wrenpp_with_name_guessing')
global_compiler_opts += ['-DWRENPP_WITH_NAME_GUESSING']
endif
conf.set('POINTER_SIZE', ptr_size)
conf.set('FUNC_POINTER_SIZE', func_ptr_size)
conf.set('WRENPP_NAME', meson.project_name())
subdir('include')
subdir('src')
project_config_file = configure_file(
input: 'src/config.h.in',
output: 'config.h',
configuration: conf
)
wrenpp = library(meson.project_name(),
project_config_file,
'src/vm.cpp',
'src/configuration.cpp',
'src/def_configuration.cpp',
'src/dynafunc_maker.cpp',
'src/dynafunc_' + arch + '_' + os + '.S',
'src/handle.cpp',
'src/vm_fun.cpp',
dependencies: [wren_dep],
include_directories: public_incl,
install: true,
)
wrenpp_dep = declare_dependency(
link_with: wrenpp,
include_directories: public_incl,
)
python.extension_module('py' + meson.project_name(),
sources: [
'src/pywrenppmodule.cpp',
],
dependencies: [
python.dependency(
version: '>=3.6.0',
required: get_option('wrenpp_with_python'),
),
wrenpp_dep,
],
install: true,
)
if get_option('build_examples')
subdir('examples')

View file

@ -1,5 +1,5 @@
option('build_testing', type: 'boolean', value: false)
option('build_examples', type: 'boolean', value: false)
option('wren_with_rand', type: 'boolean', value: false)
option('wren_with_meta', type: 'boolean', value: false)
option('wrenpp_with_name_guessing', type: 'boolean', value: true)
option('wren_with_rand', type: 'boolean', value: false, yield: true)
option('wren_with_meta', type: 'boolean', value: false, yield: true)
option('wrenpp_with_python', type: 'feature', value: 'disabled')

View file

@ -1,100 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/callback_manager.hpp"
#include <algorithm>
#include <cassert>
namespace wren::detail {
FullSignatureOwning::FullSignatureOwning (std::string_view module_name, std::string_view class_name, std::string_view signature) :
FullSignatureBase(std::hash<std::string_view>{}(module_name), std::hash<std::string_view>{}(class_name), std::hash<std::string_view>{}(signature)),
StringsInVector<3>(module_name, class_name, signature)
{
}
TempFullSignature::TempFullSignature (const FullSignatureOwning& full_sig) :
FullSignatureBase(full_sig),
m_module_name(full_sig.module_name()),
m_class_name(full_sig.class_name()),
m_signature(full_sig.signature())
{ }
TempFullSignature::TempFullSignature (std::string_view module_name, std::string_view class_name, std::string_view signature) :
FullSignatureBase(std::hash<std::string_view>{}(module_name), std::hash<std::string_view>{}(class_name), std::hash<std::string_view>{}(signature)),
m_module_name(module_name),
m_class_name(class_name),
m_signature(signature)
{ }
bool FullSignatureEqual::operator()(TempFullSignature left, TempFullSignature right) const {
return left.class_name() == right.class_name() and
left.module_name() == right.module_name() and
left.signature() == right.signature();
}
std::size_t FullSignatureHash::operator() (TempFullSignature key) const {
//see example at https://en.cppreference.com/w/cpp/utility/hash
const std::size_t h1 = key.module_hash();
const std::size_t h2 = key.class_hash();
const std::size_t h3 = key.signature_hash();
return h1 ^ ((h2 ^ (h3 << 1)) << 1);
}
} //namespace wren::detail
namespace wren {
CallbackManager::CallbackManager() = default;
CallbackManager::~CallbackManager() noexcept = default;
CallbackManager& CallbackManager::add_callback (
bool is_static,
std::string_view module_name,
std::string_view class_name,
std::string_view signature,
std::function<foreign_method_t()> make_cb
) {
using detail::FullSignatureOwning;
using detail::TempFullSignature;
MethodMap& map = *method_map(is_static);
auto it_found = map.find(TempFullSignature{module_name, class_name, signature});
if (map.cend() == it_found)
map.insert(it_found, std::make_pair(FullSignatureOwning{module_name, class_name, signature}, make_cb()));
else
it_found->second = make_cb();
return *this;
}
foreign_method_t CallbackManager::callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature) const {
using detail::TempFullSignature;
const MethodMap* const map = method_map(is_static);
const auto it_found = map->find(TempFullSignature{module_name, class_name, signature});
if (map->cend() != it_found)
return it_found->second;
else
return nullptr;
}
auto CallbackManager::method_map(bool is_static) noexcept -> MethodMap* {
return (is_static ? &m_static_methods : &m_normal_methods);
}
auto CallbackManager::method_map(bool is_static) const noexcept -> const MethodMap* {
return const_cast<CallbackManager*>(this)->method_map(is_static);
}
} //namespace wren

View file

@ -1,147 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/class_manager.hpp"
#include <cassert>
namespace wren {
namespace detail {
ClassNameBase::ClassNameBase (const std::string_view& module_name, const std::string_view& class_name) :
m_module_hash(std::hash<std::string_view>{}(module_name)),
m_class_name_hash(std::hash<std::string_view>{}(class_name))
{
}
bool ClassNameBase::operator==(const ClassNameBase& other) const {
return m_module_hash == other.m_module_hash and
m_class_name_hash == other.m_class_name_hash;
}
ClassNameOwning::ClassNameOwning(const std::string_view& module_name, const std::string_view& class_name) :
StringsInVector<2>(module_name, class_name),
ClassNameBase(module_name, class_name)
{
}
ClassNameOwning::operator ModuleAndName() const {
return ModuleAndName{
this->raw_buffer(),
this->module_name().size(),
this->class_name().size()
};
}
bool ClassNameOwning::operator== (const ClassNameOwning& other) const {
return
*static_cast<const ClassNameBase*>(this) == static_cast<const ClassNameBase&>(other) or
*static_cast<const StringsInVector<2>*>(this) == static_cast<const StringsInVector<2>&>(other);
}
TempClassName::TempClassName(std::string_view module_name, std::string_view class_name) :
ClassNameBase(module_name, class_name),
m_module_name(module_name),
m_class_name(class_name)
{
}
TempClassName::TempClassName (const ClassNameOwning& other) :
ClassNameBase(other),
m_module_name(other.module_name()),
m_class_name(other.class_name())
{
}
bool TempClassName::operator== (const TempClassName& other) const {
return *static_cast<const ClassNameBase*>(this) == static_cast<const ClassNameBase&>(other) and
m_module_name == other.m_module_name and
m_class_name == other.m_class_name;
}
bool ClassNameEqual::operator()(TempClassName left, TempClassName right) const {
return left == right;
}
std::size_t ClassNameHash::operator()(TempClassName value) const {
return value.module_hash() ^ (value.class_hash() << 1);
}
std::size_t TypeIDHash::operator()(TypeID tid) const {
if constexpr (sizeof(tid.id()) > sizeof(std::size_t)) {
return std::hash<decltype(tid.id())>{}(tid.id());
}
else {
return static_cast<std::size_t>(tid.id());
}
}
} //namespace detail
ClassManager::ClassManager() = default;
ClassManager::~ClassManager() noexcept = default;
foreign_class_t ClassManager::make_class (std::string_view module_name, std::string_view class_name) {
using detail::TempClassName;
auto it_found = m_classes.find(TempClassName{module_name, class_name});
if (m_classes.cend() != it_found)
return it_found->second();
else
return {nullptr, nullptr};
}
auto ClassManager::add_class_maker_implem (
std::string_view module_name,
std::string_view class_name,
make_foreign_class_t maker
) -> ClassMap::const_iterator {
using detail::TempClassName;
using detail::ClassNameOwning;
auto it_found = m_classes.find(TempClassName{module_name, class_name});
ClassMap::const_iterator retval;
if (m_classes.cend() == it_found) {
retval = m_classes.insert(
it_found,
std::make_pair(ClassNameOwning{module_name, class_name}, maker)
);
}
else {
it_found->second = maker;
retval = it_found;
}
return retval;
}
void ClassManager::add_type (TypeID hash, const detail::ClassNameOwning* name) {
using detail::TempClassName;
assert(m_types.count(hash) == 0 or *m_types.at(hash) == *name);
//insert if not present, leave old value if hash is already there
m_types.insert(std::make_pair(hash, name));
}
ModuleAndName ClassManager::wren_class_name_from_hash(TypeID hash) const {
const auto it_found = m_types.find(hash);
if (m_types.cend() != it_found) {
const detail::ClassNameOwning* const name = it_found->second;
return *name;
}
else {
return {};
}
}
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify

View file

@ -1,59 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/detail/crc32.hpp"
#include "crc32_config.h"
namespace wren::detail {
#if HAVE_NEON
[[gnu::const]] bool has_crc32_neon() noexcept;
[[gnu::pure]] std::uint32_t crc32c_neon(const char*, std::size_t, std::uint32_t) noexcept;
#endif
#if HAVE_SSE42
[[gnu::const]] bool has_crc32_sse42() noexcept;
[[gnu::pure]] std::uint32_t crc32c_sse42(const char*, std::size_t, std::uint32_t) noexcept;
#endif
} //namespace wren::detail
namespace wren::detail {
//Some useful polynomials:
// zlib: 0x04C11DB7
// castagnoli (intel): 0x1EDC6F41
namespace {
[[gnu::const]]
auto best_crc32_function() {
#if HAVE_NEON
if (has_crc32_neon())
return &crc32c_neon;
#endif
#if HAVE_SSE42
if (has_crc32_sse42())
return &crc32c_sse42;
#endif
return &crc32<detail::g_castagnoli_polynomial>;
}
} //unnamed namespace
[[gnu::const]]
std::uint32_t runtime_crc32c (const char* data, std::size_t size, std::uint32_t crc) {
static const auto crc32c_implem = best_crc32_function();
return (*crc32c_implem)(data, size, crc);
}
} //namespace wren::detail

View file

@ -1,104 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include <sys/auxv.h>
#include <asm/hwcap.h>
#include <cstdint>
// Byte-boundary alignment issues
#define CALC_CRC(op, crc, type, buf, len) \
do { \
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
(crc) = op((crc), *(type *) (buf)); \
} \
} while(0)
namespace wren::detail {
//King_DuckZ - adapted from
//https://github.com/rurban/smhasher/blob/master/sse2neon.h
namespace {
[[gnu::always_inline]] [[gnu::const]]
inline std::uint32_t neon_crc32cb(std::uint32_t crc, std::uint8_t v) {
__asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t"
: [c] "+r"(crc)
: [v] "r"(v));
return crc;
}
[[gnu::always_inline]] [[gnu::const]]
inline std::uint32_t neon_crc32ch (std::uint32_t crc, std::uint16_t v) {
__asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t"
: [c] "+r"(crc)
: [v] "r"(v));
return crc;
}
[[gnu::always_inline]] [[gnu::const]]
inline std::uint32_t neon_crc32cw(std::uint32_t crc, std::uint32_t v) {
__asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t"
: [c] "+r"(crc)
: [v] "r"(v));
return crc;
}
[[gnu::always_inline]] [[gnu::const]]
inline std::uint64_t neon_crc32cx (std::uint64_t crc, std::uint64_t v) {
__asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t"
: [c] "+r"(crc)
: [v] "r"(v));
return crc;
}
} //unnamed namespace
[[gnu::const]]
bool has_crc32_neon() noexcept {
//see
//https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/runtime-detection-of-cpu-features-on-an-armv8-a-cpu
const bool has_hw_crc32 = (getauxval(AT_HWCAP) & HWCAP_CRC32 ? true : false);
return has_hw_crc32;
}
/* Compute CRC-32C using the Intel hardware instruction. */
/* for better parallelization with bigger buffers see
http://www.drdobbs.com/parallel/fast-parallelized-crc-computation-using/229401411 */
[[gnu::pure]]
std::uint32_t crc32c_neon(const char* input, std::size_t len, std::uint32_t crc) noexcept {
//see https://github.com/rurban/smhasher/blob/master/crc32_hw.c
constexpr std::size_t align_size = alignof(std::uint64_t);
constexpr std::size_t align_mask = align_size - 1;
// XOR the initial CRC with INT_MAX
//crc ^= 0xFFFFFFFF;
crc = ~crc;
// Align the input to the word boundary
for (; (len > 0) && (reinterpret_cast<std::uintptr_t>(input) & align_mask); len--, input++) {
crc = neon_crc32cb(crc, *input);
}
// Blast off the CRC32 calculation
#if defined(__x86_64__) || defined(__aarch64__)
CALC_CRC(neon_crc32cx, crc, std::uint64_t, input, len);
#endif
CALC_CRC(neon_crc32cw, crc, std::uint32_t, input, len);
CALC_CRC(neon_crc32ch, crc, std::uint16_t, input, len);
CALC_CRC(neon_crc32cb, crc, std::uint8_t, input, len);
// Post-process the crc
return ~crc;
}
} //namespace wren::detail

View file

@ -1,66 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include <smmintrin.h>
#include <immintrin.h>
#include <cstdint>
// Byte-boundary alignment issues
#define CALC_CRC(op, crc, type, buf, len) \
do { \
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
(crc) = op((crc), *(type *) (buf)); \
} \
} while(0)
namespace wren::detail {
[[gnu::const]]
bool has_crc32_sse42() noexcept {
const bool has_hw_crc32 = (__builtin_cpu_supports("sse4.2") ? true : false);
return has_hw_crc32;
}
/* Compute CRC-32C using the Intel hardware instruction. */
/* for better parallelization with bigger buffers see
http://www.drdobbs.com/parallel/fast-parallelized-crc-computation-using/229401411 */
[[gnu::pure]]
std::uint32_t crc32c_sse42(const char* input, std::size_t len, std::uint32_t crc) noexcept {
//see https://github.com/rurban/smhasher/blob/master/crc32_hw.c
constexpr std::size_t align_size = alignof(std::uint64_t);
constexpr std::size_t align_mask = align_size - 1;
// XOR the initial CRC with INT_MAX
//crc ^= 0xFFFFFFFF;
crc = ~crc;
// Align the input to the word boundary
for (; (len > 0) && (reinterpret_cast<std::uintptr_t>(input) & align_mask); len--, input++) {
crc = _mm_crc32_u8(crc, *input);
}
// Blast off the CRC32 calculation
#if defined(__x86_64__) || defined(__aarch64__)
CALC_CRC(_mm_crc32_u64, crc, std::uint64_t, input, len);
#endif
CALC_CRC(_mm_crc32_u32, crc, std::uint32_t, input, len);
CALC_CRC(_mm_crc32_u16, crc, std::uint16_t, input, len);
CALC_CRC(_mm_crc32_u8, crc, std::uint8_t, input, len);
// Post-process the crc
return ~crc;
}
} //namespace wren::detail

View file

@ -1,40 +0,0 @@
simd = import('unstable-simd')
compiler_opts = []
if arch == 'amd64'
compiler_opts += ['-msse4.2']
elif arch == 'aarch64'
#gcc options here:
#https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/AArch64-Options.html
compiler_opts += ['-mcpu=generic+crc']
endif
cpp = meson.get_compiler('cpp')
crc32_simd = simd.check('crc32_hw',
sse42: 'crc32_sse42.cpp',
neon: 'crc32_neon.cpp',
compiler: cpp,
cpp_args: compiler_opts,
)
crc32_objs = crc32_simd[0]
crc32_config = crc32_simd[1]
project_config_file = configure_file(
output: 'crc32_config.h',
configuration: crc32_config
)
crc32 = static_library('crc32',
'crc32.cpp',
include_directories: [public_incl],
install: false,
cpp_args: global_compiler_opts,
link_with: crc32_objs,
)
crc32_dep = declare_dependency(
include_directories: public_incl,
link_with: crc32,
compile_args: global_compiler_opts,
)

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -16,52 +16,37 @@
*/
#include "wrenpp/def_configuration.hpp"
#include "wrenpp/callback_manager.hpp"
#include "wrenpp/class_manager.hpp"
#include "wrenpp/vm.hpp"
#include <iostream>
#include <algorithm>
#include <cstdlib>
namespace wren {
namespace {
template <typename T>
bool empty(T* message) {
return not (message and *message);
}
} //unnamed namespace
void DefConfiguration::write_fn (VM*, wren_string_t text) {
void DefConfiguration::write_fn (VM*, const char* text) {
std::cout << text;
}
void DefConfiguration::error_fn (VM*, ErrorType type, wren_string_t module, int line, wren_string_t message) {
using std::empty;
std::cerr << "Wren error: " << message;
if (!empty(module)) {
std::cerr << " in " << module;
if (line > -1) {
std::cerr << ':' << line;
}
}
std::cerr << '\n';
void DefConfiguration::error_fn (VM*, ErrorType type, const char* module, int line, const char* message) {
std::cerr << "Wren error: " << message << " in " << module << ':' << line << '\n';
}
void* DefConfiguration::reallocate_fn (void* ptr, std::size_t size) {
if (0 == size) {
std::free(ptr);
return nullptr;
if (ptr and size) {
//reallocate
char* const old_mem = static_cast<char*>(ptr);
char* const new_mem = new char[size];
std::copy(old_mem, old_mem + size, new_mem);
delete[] old_mem;
return new_mem;
}
return std::realloc(ptr, size);
}
foreign_method_t DefConfiguration::foreign_method_fn (VM* vm, wren_string_t module_name, wren_string_t class_name, bool is_static, wren_string_t signature) {
return vm->callback_manager().callback(is_static, module_name, class_name, signature);
}
foreign_class_t DefConfiguration::foreign_class_fn (wren::VM* vm, std::string_view module_name, std::string_view class_name) {
return vm->class_manager().make_class(module_name, class_name);
else if (ptr and not size) {
//free
char* const old_mem = static_cast<char*>(ptr);
delete[] old_mem;
}
else if (not ptr and size) {
//allocate
char* const new_mem = new char[size];
return new_mem;
}
return nullptr;
}
} //namespace wren

View file

@ -1,37 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#as --march=generic64 -o dynafunc.o ~/dev/code/cpp/wrentest/src/dynafunc.asm
#objcopy -j .text -O binary dynafunc.o dynafunc.bin
#xxd -i dynafunc.bin
.global g_dynafunc
.global g_dynafunc_end
.section .note.GNU-stack,"",@progbits
.text
g_dynafunc:
ldr x0, .+20
ldr x1, .+24
ldr x2, .+28
ldr x9, .+32
br x9
.dword 0xdeadbeefdeadbeef //function VM& parameter
.dword 0x1badb0021badb002 //ModuleAndName parameter, string part
.dword 0xfee1deadfee1dead //ModuleAndName parameter, data part
.dword 0xbadc0ffee0ddf00d //function pointer
g_dynafunc_end:

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -21,19 +21,10 @@
.global g_dynafunc
.global g_dynafunc_end
.section .note.GNU-stack,"",@progbits
.text
g_dynafunc:
//VM pointer, parameter 1
movabsq $0xdeadbeefdeadbeef, %rdi
//ModuleAndName string part, parameter 2
movabsq $0x1badb0021badb002, %rsi
//ModuleAndName data part, parameter 3
movabsq $0xfee1deadfee1dead, %rdx
//jump address
movabsq $0xbadc0ffee0ddf00d, %rax
jmp *%rax
movq $0xdeadbeefdeadbeef, %rdi
movq $0xbadc0ffee0ddf00d, %rdx
jmp *%rdx
ret
g_dynafunc_end:

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -21,8 +21,7 @@
#endif
#include "dynafunc_maker.hpp"
#include "pvt_config.h"
#include "wrenpp/detail/strings_in_vector.hpp"
#include "config.h"
#include <algorithm>
#include <cassert>
#include <unistd.h> //for sysconf()
@ -32,8 +31,6 @@
#include <sys/mman.h> //for mprotect()
#include <memory>
#include <new>
#include <string_view>
#include <type_traits>
namespace wren {
namespace {
@ -45,18 +42,10 @@ namespace wren {
extern "C" const char g_dynafunc_end[];
const unsigned int g_dynafunc_len = g_dynafunc_end - g_dynafunc;
constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_PTR_SIZE;
//For inspiration: https://www.liquisearch.com/deadbeef/magic_debug_values
//0xdeadbeefdeadbeef
constexpr unsigned char g_dynafunc_ptr1[] = {0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde};
//0xbadc0ffee0ddf00d
constexpr unsigned char g_dynafunc_ptr2[] = {0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba};
//0x1badb0021badb002
constexpr unsigned char g_dynafunc_ptr3[] = {0x02, 0xb0, 0xad, 0x1b, 0x02, 0xb0, 0xad, 0x1b};
//0xfee1deadfee1dead
constexpr unsigned char g_dynafunc_ptr4[] = {0xad, 0xde, 0xe1, 0xfe, 0xad, 0xde, 0xe1, 0xfe};
const constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
const constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_PTR_SIZE;
const constexpr unsigned char g_dynafunc_ptr1[] = {0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde};
const constexpr unsigned char g_dynafunc_ptr2[] = {0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba};
static_assert(sizeof(g_dynafunc_ptr1) / sizeof(g_dynafunc_ptr1[0]) >= g_dynafunc_ptr1_size);
static_assert(sizeof(g_dynafunc_ptr2) / sizeof(g_dynafunc_ptr2[0]) >= g_dynafunc_ptr2_size);
@ -74,51 +63,11 @@ namespace wren {
std::copy(ptr, ptr + sizeof(T), subseq);
}
void make_dynafunc_asm(
unsigned char* out,
VM* ptr1,
foreign_method_t ptr2,
RawAccessModuleAndName mn
) {
static_assert(std::is_standard_layout<ModuleAndName>::value,
"Must be a standard layout to be compliant with the assembly functions");
static_assert(sizeof(void*) * 2 == sizeof(ModuleAndName),
"Must fit into 2 registers to be compliant with the assembly functions");
void make_dynafunc_asm(unsigned char* out, VM* ptr1, foreign_method_t ptr2) {
std::copy(g_dynafunc, g_dynafunc_end, out);
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr1, ptr1);
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr2, ptr2);
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr3, mn.raw.string);
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr4, mn.raw.data);
}
ModuleAndName store_module_name (
std::list<std::vector<char>>& dst,
std::string_view mod_name,
std::string_view cls_name
) {
typedef std::vector<char> CharVec;
CharVec new_entry = strings_to_vector(mod_name, cls_name);
const auto it_found = std::lower_bound(
dst.cbegin(),
dst.cend(),
new_entry,
[](const CharVec& a, const CharVec& b) {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
);
const CharVec* source_mem;
if (dst.cend() != it_found && std::equal(it_found->cbegin(), it_found->cend(), new_entry.cbegin(), new_entry.cend())) {
source_mem = &*it_found;
}
else {
source_mem = &*dst.insert(it_found, std::move(new_entry));
}
return {source_mem->data(), mod_name.size(), cls_name.size()};
}
} //unnamed namespace
@ -137,11 +86,9 @@ namespace wren {
clear();
}
void* DynafuncMaker::make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name) {
void* DynafuncMaker::make (VM* vm, foreign_method_t cb) {
unsigned char* const mem = allocate_chunk();
const auto mn = store_module_name(m_string_params, mod_name, cls_name);
make_dynafunc_asm(mem, vm, cb, mn);
make_dynafunc_asm(mem, vm, cb);
return mem;
}
@ -154,9 +101,7 @@ namespace wren {
}
std::size_t DynafuncMaker::total_memory() const {
return m_pages.size() * m_page_size +
m_pages.capacity() * sizeof(decltype(m_pages)::value_type) +
0;
return m_pages.size() * m_page_size;
}
unsigned char* DynafuncMaker::allocate_chunk() {

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,18 +17,19 @@
#pragma once
#include "wrenpp/detail/wren_types.hpp"
#include <vector>
#include <list>
#include <cstddef>
namespace wren {
class VM;
typedef void(*foreign_method_t)(VM&);
class DynafuncMaker {
public:
DynafuncMaker();
~DynafuncMaker() noexcept;
void* make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name);
void* make (VM* vm, foreign_method_t cb);
void clear() noexcept;
std::size_t total_memory() const;
@ -36,7 +37,6 @@ namespace wren {
private:
unsigned char* allocate_chunk();
std::list<std::vector<char>> m_string_params;
std::vector<void*> m_pages;
std::size_t m_page_size;
std::size_t m_used_bytes;

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -18,25 +18,14 @@
#include "wrenpp/handle.hpp"
#include "wrenpp/vm.hpp"
#include <cassert>
#include <ciso646>
namespace wren {
Handle::Handle (VM* vm, int slot_num) :
Handle(vm->slot_handle(slot_num))
{
}
Handle::~Handle() noexcept {
release();
}
void Handle::release() noexcept {
assert(m_vm or not m_handle);
if (m_vm)
m_vm->release_handle(*this);
}
void Handle::set_to_slot (int slot) {
m_vm->set_slot_handle(*this, slot);
assert(m_vm);
m_vm->release_handle(*this);
}
} //namespace wren

View file

@ -1,36 +0,0 @@
subdir('crc32')
project_config_file = configure_file(
input: 'pvt_config.h.in',
output: 'pvt_config.h',
configuration: conf
)
wrenpp = library(meson.project_name(),
project_config_file,
'vm.cpp',
'configuration.cpp',
'def_configuration.cpp',
'dynafunc_maker.cpp',
'dynafunc_' + arch + '_' + os + '.S',
'handle.cpp',
'vm_fun.cpp',
'callback_manager.cpp',
'class_manager.cpp',
'wren_class_name_from_type.cpp',
'module_and_name.cpp',
'setters_getters.cpp',
dependencies: [wren_dep, crc32_dep],
include_directories: public_incl,
install: (not meson.is_subproject() or get_option('default_library')=='shared'),
c_args: global_compiler_opts,
cpp_args: global_compiler_opts,
)
wrenpp_dep = declare_dependency(
link_with: wrenpp,
include_directories: public_incl,
compile_args: global_compiler_opts,
)
meson.override_dependency(meson.project_name(), wrenpp_dep)

View file

@ -1,30 +0,0 @@
/* Copyright 2020-2022, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/detail/module_and_name.hpp"
#include <algorithm>
namespace wren::detail {
bool deep_equal(const ModuleAndName& a, const ModuleAndName& b) noexcept {
const auto a_size = a.raw_buffer_size();
const auto b_size = b.raw_buffer_size();
if (a_size != b_size)
return false;
return std::equal(a.m_base, a.m_base + a_size, b.m_base);
}
} //namespace wren::detail

178
src/pywrenppmodule.cpp Normal file
View file

@ -0,0 +1,178 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "wrenpp/vm.hpp"
#include "wrenpp/vm_fun.hpp"
#include "wrenpp/def_configuration.hpp"
#include "config.h"
#include <vector>
#include <string_view>
#include <string>
#define CURR_MODULE_NAME "py" WRENPP_NAME
namespace {
struct VMObject;
int vm_init (VMObject* self, PyObject*, PyObject*);
PyObject* vm_new (PyTypeObject* type, PyObject*, PyObject*);
void vm_dealloc (VMObject* self);
PyObject* vm_interpret (VMObject* self, PyObject* args);
PyObject* vm_call (VMObject* self, PyObject* args);
class VMConfig : public wren::DefConfiguration {
public:
wren::foreign_method_t foreign_method_fn (
wren::VM* vm,
const char* module_ptr,
const char* class_name_ptr,
bool is_static,
const char* signature_ptr
) {
return nullptr;
}
};
PyMethodDef WrenppMethods[] = {
//{"eval_script", &eval_script, METH_VARARGS, "Evaluate a Wren script"},
{nullptr, nullptr, 0, nullptr}
};
struct PyModuleDef WrenppModule = {
PyModuleDef_HEAD_INIT,
CURR_MODULE_NAME, //module name
"Python bindings for Wrenpp", //module documentation
-1, //size of per-interpreter state of the module, or -1 if the module keeps state in global variables
WrenppMethods
};
struct VMObject {
PyObject_HEAD
wren::VM vm;
};
//PyMemberDef VMProperties[] = {
// {nullptr}
//};
PyMethodDef VMMethods[] = {
{
"interpret",
reinterpret_cast<PyCFunction>(vm_interpret),
METH_VARARGS,
"Interpret a string script"
},
{
"call",
reinterpret_cast<PyCFunction>(vm_call),
METH_VARARGS,
"Call a method from a previously parsed script"
},
{nullptr}
};
PyTypeObject VMType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = CURR_MODULE_NAME ".VM",
.tp_basicsize = sizeof(VMObject),
.tp_itemsize = 0,
.tp_dealloc = reinterpret_cast<destructor>(vm_dealloc),
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Wrenpp VM",
.tp_methods = VMMethods,
.tp_members = nullptr, //VMProperties,
.tp_init = reinterpret_cast<initproc>(vm_init),
.tp_new = vm_new,
};
PyObject* vm_new (PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwds*/) {
VMObject* const self = reinterpret_cast<VMObject*>(type->tp_alloc(type, 0));
if (self) {
try {
VMConfig config;
new(&self->vm) wren::VM(&config, nullptr);
}
catch (...) {
Py_DECREF(self);
return nullptr;
}
}
return reinterpret_cast<PyObject*>(self);
}
void vm_dealloc (VMObject* self) {
self->vm.~VM();
}
int vm_init (VMObject* self, PyObject* /*args*/, PyObject* /*kwds*/) {
VMConfig config;
self->vm.reset(&config);
return 0;
}
PyObject* vm_interpret (VMObject* self, PyObject* args) {
const char* module_name;
const char* script;
if (!PyArg_ParseTuple(args, "ss", &module_name, &script))
return NULL;
self->vm.interpret(module_name, script);
Py_RETURN_NONE;
}
PyObject* vm_call (VMObject* self, PyObject* args) {
const Py_ssize_t argc = PyTuple_Size(args);
std::vector<PyObject*> objects;
objects.reserve(argc);
self->vm.ensure_slots(static_cast<std::size_t>(argc) + 1);
variable(self->vm, wren::ModuleAndName{"main", "the_user"}, 0);
//TODO: missing error checks, see
//https://stackoverflow.com/questions/8001923/python-extension-module-with-variable-number-of-arguments
std::string func_sig;
{
Py_ssize_t sz;
PyObject* const obj = PyTuple_GetItem(args, 0);
const char* const buf = PyUnicode_AsUTF8AndSize(obj, &sz);
func_sig.reserve(sz + 3);
func_sig.append(buf, sz);
func_sig.append(1, '(');
}
for (Py_ssize_t z = 1; z < argc; ++z) {
PyObject* const obj = PyTuple_GetItem(args, z);
if (not obj)
return nullptr;
const std::string_view type_name(Py_TYPE(obj)->tp_name);
//std::cout << "vm_call, parameter " << z+1 << " has type \"" << type_name << "\"\n";
if (type_name == "str") {
const char* const buf = PyUnicode_AsUTF8(obj);
self->vm.set_slot_string(static_cast<std::size_t>(z), buf);
}
func_sig += "_,";
}
if (func_sig.back() == ',')
func_sig.resize(func_sig.size() - 1);
func_sig += ")";
auto handle = self->vm.make_call_handle(func_sig.c_str());
self->vm.call(handle);
Py_RETURN_NONE;
}
} //unnamed namespace
PyMODINIT_FUNC PyInit_pywrenpp(void) {
if (PyType_Ready(&VMType) < 0)
return nullptr;
PyObject* const m = PyModule_Create(&WrenppModule);
if (not m)
return nullptr;
Py_INCREF(&VMType);
if (PyModule_AddObject(m, "VM", reinterpret_cast<PyObject*>(&VMType)) < 0) {
Py_DECREF(&VMType);
Py_DECREF(m);
return nullptr;
}
return m;
}

View file

@ -1,21 +0,0 @@
/* Copyright 2020-2024, 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 <http://www.gnu.org/licenses/>.
*/
#include "wrenpp/detail/setters_getters.hpp"
namespace wren {
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -17,8 +17,6 @@
#include "wrenpp/vm.hpp"
#include "wrenpp/configuration.hpp"
#include "wrenpp/callback_manager.hpp"
#include "wrenpp/class_manager.hpp"
#include "dynafunc_maker.hpp"
#include <wren.hpp>
#include <cassert>
@ -36,8 +34,6 @@ namespace wren {
};
}
void load_module_complete_fn (WrenVM* wvm, const char* name, struct WrenLoadModuleResult result);
void write_fn (WrenVM* wvm, const char* text) {
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
assert(cb);
@ -49,8 +45,7 @@ namespace wren {
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
assert(cb);
assert(cb->error_fn and cb->config_obj and cb->owner);
const char* const sane_module = (module ? module : "");
cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), sane_module, line, message);
cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), module, line, message);
}
const char* resolve_module_fn (WrenVM* wvm, const char* importer, const char* name) {
@ -60,25 +55,11 @@ namespace wren {
return cb->resolve_module_fn(*cb->config_obj, cb->owner, importer, name);
}
void* reallocate_fn (void* memory, size_t size, void* user_data) {
auto cb = static_cast<detail::Callbacks*>(user_data);
assert(cb);
assert(cb->reallocate_fn);
return cb->reallocate_fn(memory, size);
}
WrenLoadModuleResult load_module_fn (WrenVM* wvm, const char* name) {
const auto user_data = wrenGetUserData(wvm);
auto cb = static_cast<detail::Callbacks*>(user_data);
char* load_module_fn (WrenVM* wvm, const char* name) {
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
assert(cb);
assert(cb->load_module_fn and cb->config_obj and cb->owner);
char* const source = cb->load_module_fn(*cb->config_obj, cb->owner, name);
return ::WrenLoadModuleResult{
.source = source,
.onComplete = (cb->load_module_complete_fn ? &load_module_complete_fn : nullptr),
.userData = nullptr
};
return cb->load_module_fn(*cb->config_obj, cb->owner, name);
}
WrenForeignMethodFn foreign_method_fn (WrenVM* wvm, const char* module, const char* class_name, bool is_static, const char* signature) {
@ -89,18 +70,7 @@ namespace wren {
if (func) {
DynafuncMaker* const dfm = cb->dynafunc;
assert(dfm);
//dfm->make creates a function that takes one WrenVM* parameter
//which it disregards; then it calls func passing cb->owner to
//it and a ModuleAndName object populated with the values given
//here. This should rarely change, but please double check if
//this is important to you as this comment might become
//outdated.
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
cb->owner,
func,
module,
class_name
));
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, func));
return retval;
}
else {
@ -108,18 +78,6 @@ namespace wren {
}
}
void load_module_complete_fn (WrenVM* wvm, const char* name, struct WrenLoadModuleResult result) {
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
assert(cb);
assert(cb->load_module_complete_fn and cb->config_obj and cb->owner);
//Documentation says result is the same object we returned from
//load_module_fn. It should then be safe to const_cast source,
//since it wasn't const when we got it there
char* const non_const_buff = const_cast<char*>(result.source);
(*cb->load_module_complete_fn)(*cb->config_obj, cb->owner, name, non_const_buff);
}
WrenForeignClassMethods foreign_class_fn (WrenVM* wvm, const char* module, const char* class_name) {
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
assert(cb);
@ -129,12 +87,7 @@ namespace wren {
if (funcs.allocate) {
DynafuncMaker* const dfm = cb->dynafunc;
assert(dfm);
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
cb->owner,
funcs.allocate,
module,
class_name
));
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, funcs.allocate));
}
else {
retval.allocate = nullptr;
@ -162,8 +115,7 @@ namespace wren {
struct VM::LocalData {
explicit LocalData (const detail::Callbacks& cb) :
callbacks(cb),
wvm(nullptr),
user_data_type(type_id<std::nullptr_t>())
wvm(nullptr)
{
callbacks.dynafunc = &dynafunc;
}
@ -175,16 +127,14 @@ namespace wren {
#endif
}
CallbackManager callback_manager;
ClassManager class_manager;
detail::Callbacks callbacks;
DynafuncMaker dynafunc;
WrenVM* wvm;
void* user_data;
TypeID user_data_type;
std::uint32_t user_data_type;
};
VM::VM (Configuration* conf, const detail::Callbacks& cb, void* user_data, TypeID user_data_type) :
VM::VM (Configuration* conf, const detail::Callbacks& cb, void* user_data, std::uint32_t user_data_type) :
m_local(std::make_unique<LocalData>(cb))
{
this->reset(conf);
@ -198,7 +148,7 @@ namespace wren {
return &m_local->dynafunc;
}
TypeID VM::user_data_type() const {
std::uint32_t VM::user_data_type() const {
return m_local->user_data_type;
}
@ -206,7 +156,7 @@ namespace wren {
return m_local->user_data;
}
void VM::set_user_data (void* user_data, TypeID user_data_type) {
void VM::set_user_data (void* user_data, std::uint32_t user_data_type) {
m_local->user_data = user_data;
m_local->user_data_type = user_data_type;
}
@ -282,26 +232,13 @@ namespace wren {
void VM::set_user_data (std::nullptr_t) {
m_local->user_data = nullptr;
m_local->user_data_type = type_id<std::nullptr_t>();
m_local->user_data_type = detail::type_id<std::nullptr_t>();
}
bool VM::has_user_data() const noexcept {
bool VM::has_user_data() const {
return nullptr != m_local->user_data;
}
bool VM::has_module(const char* module) const noexcept {
assert(module);
return wrenHasModule(m_local->wvm, module);
}
bool VM::has_variable(const char* module, const char* name) const noexcept {
return wrenHasVariable(m_local->wvm, module, name);
}
void VM::abort_fiber(int slot_num) {
wrenAbortFiber(m_local->wvm, slot_num);
}
std::size_t VM::dynafunc_byte_size() const {
return m_local->dynafunc.total_memory();
}
@ -323,7 +260,7 @@ namespace wren {
wconf.errorFn = &error_fn;
if (cb.reallocate_fn)
wconf.reallocateFn = &reallocate_fn;
wconf.reallocateFn = cb.reallocate_fn;
if (cb.resolve_module_fn)
wconf.resolveModuleFn = &resolve_module_fn;
@ -346,22 +283,6 @@ namespace wren {
m_local->dynafunc.clear();
}
CallbackManager& VM::callback_manager() {
return m_local->callback_manager;
}
const CallbackManager& VM::callback_manager() const {
return m_local->callback_manager;
}
ClassManager& VM::class_manager() {
return m_local->class_manager;
}
const ClassManager& VM::class_manager() const {
return m_local->class_manager;
}
void VM::ensure_slots (int num_slots) {
wrenEnsureSlots(m_local->wvm, num_slots);
}
@ -370,23 +291,10 @@ namespace wren {
return wrenGetSlotCount(m_local->wvm);
}
void VM::variable(const char* module, const char* name, int slot) noexcept {
assert(slot_count() >= 1);
void VM::variable(const char* module, const char* name, int slot) {
wrenGetVariable(m_local->wvm, module, name, slot);
}
void VM::variable_or_throw(const char* module, const char* name, int slot) {
using std::string;
using std::runtime_error;
if (not has_module(module))
throw runtime_error(string{"Module "} + module + " is unknown");
if (not has_variable(module, name))
throw runtime_error(string{"Variable "} + module + "::" + name + " not found");
variable(module, name, slot);
}
void VM::set_slot_handle (const Handle& handle, int slot) {
wrenSetSlotHandle(m_local->wvm, slot, handle);
}
@ -401,7 +309,6 @@ namespace wren {
case WREN_TYPE_STRING: return SlotType::String;
case WREN_TYPE_FOREIGN: return SlotType::Foreign;
case WREN_TYPE_UNKNOWN: return SlotType::Unknown;
case WREN_TYPE_MAP: return SlotType::Map;
};
assert(false);
return SlotType::Unknown;

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -72,26 +72,11 @@ namespace wren {
return std::vector<char>{arr.first, arr.first + arr.second};
}
void variable(VM& vm, ModuleAndName mod_and_name, int slot) {
vm.variable_or_throw(mod_and_name.module_name_char(), mod_and_name.class_name_char(), slot);
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot) {
vm.variable(std::get<0>(mod_and_name), std::get<1>(mod_and_name), slot);
}
void variable (VM& vm, const Handle& handle, int slot) {
vm.set_slot_handle(handle, slot);
}
void variable_ensure_slot(VM& vm, ModuleAndName mod_and_name, int slot) {
vm.ensure_slots(1);
variable(vm, mod_and_name, slot);
}
void variable_ensure_slot (VM& vm, const Handle& handle, int slot) {
vm.ensure_slots(1);
variable(vm, handle, slot);
}
void abort_fiber_with_error (VM& vm, int slot, std::string_view message) {
set(vm, slot, message);
vm.abort_fiber(slot);
}
} //namespace wren

View file

@ -1,14 +0,0 @@
#include "wrenpp/detail/wren_class_name_from_type.hpp"
#include "wrenpp/vm.hpp"
#include "wrenpp/class_manager.hpp"
namespace wren {
namespace detail {
ModuleAndName fetch_class_name_from_manager (
const VM& vm,
TypeID hash
) {
return vm.class_manager().wren_class_name_from_hash(hash);
}
} //namespace detail
} //namespace wren

View file

@ -1,8 +0,0 @@
[wrap-git]
url = https://github.com/wren-lang/wren.git
revision = 4a18fc489f9ea3d253b20dd40f4cdad0d6bb40eb
patch_directory = wren
[provide]
dependency_names = wren-0.4.0
wren = wren_dep

View file

@ -1,5 +1,5 @@
project('wren', 'c',
version: '0.4.0',
version: '0.3.0',
meson_version: '>=0.54.0',
default_options: ['buildtype=release', 'c_std=c99', 'build_testing=true'],
)
@ -17,27 +17,27 @@ else
c_opts += '-DWREN_OPT_META=0'
endif
wren_incl = include_directories('src/include', is_system: true)
wren_pvt_incl = include_directories('src/vm', 'src/optional')
test_incl = include_directories('test')
wren_incl = include_directories('wren/src/include', is_system: true)
wren_pvt_incl = include_directories('wren/src/vm', 'wren/src/optional')
test_incl = include_directories('wren/test')
threads_dep = dependency('threads')
libuv_dep = c_compiler.find_library('uv', required: true)
libuv_dep = c_compiler.find_library('libuv', required: true)
m_dep = c_compiler.find_library('m', required: true)
opt_src = [
'src/optional/wren_opt_random.c',
'src/optional/wren_opt_meta.c',
'wren/src/optional/wren_opt_random.c',
'wren/src/optional/wren_opt_meta.c',
]
vm_src = [
'src/vm/wren_compiler.c',
'src/vm/wren_core.c',
'src/vm/wren_debug.c',
'src/vm/wren_primitive.c',
'src/vm/wren_utils.c',
'src/vm/wren_value.c',
'src/vm/wren_vm.c',
'wren/src/vm/wren_compiler.c',
'wren/src/vm/wren_core.c',
'wren/src/vm/wren_debug.c',
'wren/src/vm/wren_primitive.c',
'wren/src/vm/wren_utils.c',
'wren/src/vm/wren_value.c',
'wren/src/vm/wren_vm.c',
]
force_static = meson.is_subproject()
@ -69,25 +69,24 @@ if get_option('build_testing')
fs = import('fs')
test_src = [
'test/api/api_tests.c',
'test/api/benchmark.c',
'test/api/call.c',
'test/api/call_calls_foreign.c',
'test/api/call_wren_call_root.c',
'test/api/error.c',
'test/api/foreign_class.c',
'test/api/get_variable.c',
'test/api/handle.c',
'test/api/lists.c',
'test/api/maps.c',
'test/api/new_vm.c',
'test/api/reset_stack_after_call_abort.c',
'test/api/reset_stack_after_foreign_construct.c',
'test/api/resolution.c',
'test/api/slots.c',
'test/api/user_data.c',
'test/main.c',
'test/test.c',
'wren/test/api/api_tests.c',
'wren/test/api/benchmark.c',
'wren/test/api/call.c',
'wren/test/api/call_calls_foreign.c',
'wren/test/api/call_wren_call_root.c',
'wren/test/api/error.c',
'wren/test/api/foreign_class.c',
'wren/test/api/get_variable.c',
'wren/test/api/handle.c',
'wren/test/api/lists.c',
'wren/test/api/new_vm.c',
'wren/test/api/reset_stack_after_call_abort.c',
'wren/test/api/reset_stack_after_foreign_construct.c',
'wren/test/api/resolution.c',
'wren/test/api/slots.c',
'wren/test/api/user_data.c',
'wren/test/main.c',
'wren/test/test.c',
]
test_script_paths = [
@ -104,7 +103,7 @@ if get_option('build_testing')
test_scripts = run_command(
files('find_scripts.py'),
meson.current_source_dir() / 'test',
meson.current_source_dir() / 'wren/test',
test_script_paths,
).stdout().strip().split('\n')
@ -136,7 +135,7 @@ endif
if not force_static
install_headers(
'src/include/wren.h',
'src/include/wren.hpp',
'wren/src/include/wren.h',
'wren/src/include/wren.hpp',
)
endif

1
subprojects/wren/wren Submodule

@ -0,0 +1 @@
Subproject commit cd012469976d1a9da796581cd9a9591842cb0cf8

View file

@ -24,24 +24,6 @@ System.print("my_sum = %(my_sum) (expected: 19)")
var my_sub = Maths.sub(Maths.sub(8, 5), Maths.sub(20, 19)) + 1
System.print("my_sub = %(my_sub) (expected: 3)")
)script";
const constexpr char g_script_2[] = ""
R"script(class Maths {
foreign static mul(a,b)
foreign static div(a,b)
foreign static sum(a,b)
foreign static sub(a,b)
}
var my_mul_2 = Maths.mul(Maths.mul(2, 2), Maths.mul(3, 2)) - 4
System.print("my_mul_2 = %(my_mul_2) (expected: 20)")
var my_sum_2 = Maths.sum(Maths.sum(3, 4), Maths.sum(5, -1)) + 8
System.print("my_sum_2 = %(my_sum_2) (expected: 19)")
var my_sub_2 = Maths.sub(Maths.sub(8, 5), Maths.sub(20, 19)) + 1
System.print("my_sub_2 = %(my_sub_2) (expected: 3)")
)script";
class MyConfig : public wren::DefConfiguration {
@ -107,18 +89,6 @@ int main() {
wren::VM vm(&config, nullptr);
vm.interpret("main", g_script);
wren::variable_ensure_slot(vm, {"main", "my_mul"}, 0);
std::cout << "Dynafunc mem usage: " << vm.dynafunc_byte_size() << " bytes\n";
vm.reset(&config);
std::cout << "Dynafunc mem usage after reset: " << vm.dynafunc_byte_size() << " bytes\n";
vm.interpret("main", g_script_2);
{
auto [var] = wren::variables<int>(vm, wren::ModuleAndName{"main", "my_mul_2"});
std::cout << "main::my_mul2 == " << var << " (expected: 20)\n";
}
std::cout << "Dynafunc mem usage: " << vm.dynafunc_byte_size() << " bytes\n";
return 0;