by Viktor Kirilov
IMHO
#ifdef HOST_APPLICATION // export if building the application or import otherwise
#define HOST_API SYMBOL_EXPORT // __declspec(dllexport)
#else
#define HOST_API SYMBOL_IMPORT // __declspec(dllimport)
#endif
class HOST_API Object { // entire class is exported
float m_x = 0, m_y = 0, m_r = 0.3f, m_g = 0.3f, m_b = 0.3f;
float m_rot = 0, m_rot_speed = 1.f;
friend HOST_API Object& addObject(float x, float y);
Object() = default;
public:
void translate(float x, float y);
void colorize(float r, float g, float b);
void set_speed(float speed);
void draw();
};
HOST_API std::vector<Object>& getObjects();
HOST_API Object& addObject(float x, float y);
// global
int foo() { return 42; }
// vars
int a = foo();
auto& b = a;
// once
a++;
// global
#include <iostream>
void print() { std::cout << a << b << std::endl; }
// once
print(); // ======> will result in "4343" being printed
a series of shared objects for each submission
// global
#include <iostream>
// once
std::cout << "hello!";
#include "path/to/rcrl_for_plugin.h"
#include <iostream>
RCRL_ONCE_BEGIN
std::cout << "hello!";
RCRL_ONCE_END
#include "path/to/rcrl_for_plugin.h"
#include <iostream>
int rcrl_anon_12 = []() {
std::cout << "hello!";
return 0; }();
submitted code
.cpp file
expanded macros
// vars
int a = 5;
// once
a++;
#include "path/to/rcrl_for_plugin.h"
int& a = *[]() { // reference to an int called "a"
auto& address = rcrl_get_persistence("a");
if(address == nullptr) {
address = (void*)new int(5);
rcrl_add_deleter(address, [](void* ptr)
{ delete static_cast<int*>(ptr); });
}
return static_cast<int*>(address);
}(); // immediately call the lambda
int rcrl_anon_12 = []() {
a++;
return 0; }();
submitted code
expanded macros
// vars
auto a = 5;
#include "path/to/rcrl_for_plugin.h"
auto type_of_a = []() -> auto { // use with decltype() to deduce the type
auto temp = (5);
return temp;
};
decltype(type_of_a())& a = *[]() {
auto& address = rcrl_get_persistence("a");
if(address == nullptr) {
address = (void*)new decltype(type_of_a())(5);
rcrl_add_deleter(address, [](void* ptr)
{ delete static_cast<decltype(type_of_a())*>(ptr); });
}
return static_cast<decltype(type_of_a())*>(address);
}();
submitted code
expanded macros
RCRL_SYMBOL_IMPORT void*& rcrl_get_persistence(const char* var_name);
RCRL_SYMBOL_IMPORT void rcrl_add_deleter(void* address, void (*deleter)(void*));
set_target_properties(my_executable PROPERTIES ENABLE_EXPORTS ON)
#if defined _WIN32 || defined __CYGWIN__
#define SYMBOL_EXPORT __declspec(dllexport)
#define SYMBOL_IMPORT __declspec(dllimport)
#else
#define SYMBOL_EXPORT __attribute__((visibility("default")))
#define SYMBOL_IMPORT
#endif
#ifdef DLL_EXPORTS // if this is defined - the API is exported
#define MY_API SYMBOL_EXPORT
#else
#define MY_API SYMBOL_IMPORT
#endif
MY_API void bar(); // annotated free function
class MY_API MyClass {
// everything here is exported
};
The health benefits:
Cons:
too much work if only for the RCRL technique - try to export all
std::map<decltype(i_return_int()), std::vector<std::string>> m = {{5, {}}, {6, {}}};
// rcrl.h
enum Mode {
GLOBAL,
VARS,
ONCE
};
std::string cleanup_plugins(bool redirect_stdout = false);
bool submit_code(std::string code, Mode default_mode = ONCE, ...);
std::string get_new_compiler_output();
bool is_compiling();
bool try_get_exit_status_from_compile(int& exitcode);
std::string copy_and_load_new_plugin(bool redirect_stdout = false);
while(true) { // main loop of program
if(submit() && is_compiling() == false) { // submit code !!!
editor.lock(); // no editing while compiling
submit_code(editor.code()); // submit for compilation
compiler_output.clear(); // clear old output
}
compiler_output += get_new_compiler_output(); // anything new?
int status;
if(try_get_exit_status_from_compile(status)) { // check compilation
if(status == 0) { // on success
history += editor.code(); // append to history
editor.code().clear(); // clear code
copy_and_load_new_plugin(); // load/execute!
}
editor.unlock(); // unlock editor regardless of success
}
}
the editor may be separate from the application
code can be sent through sockets or some other way
easier support for auto-completion and syntax highlighting
// standard includes
#include <cmath>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <cstddef>
#include <cctype>
#include <typeinfo>
#include <functional>
#include <exception>
#include <stdexcept>
#include <iterator>
#include <limits>
#include <numeric>
#include <string>
#include <utility>
#include <memory>
#include <tuple>
#include <new>
#include <random>
#include <chrono>
#include <type_traits>
#include <vector>
#include <array>
#include <list>
#include <map>
// ...continues...
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <optional>
#include <variant>
// third party
#include <dynamix/dynamix.hpp>
#include <ppk_assert.h>
#include <sajson/include/sajson.h>
#include <GL/glew.h>
#include <yama/yama.hpp>
// project specific
#include "utils/suppress_warnings.h"
#include "utils/visibility.h"
#include "utils/preprocessor.h"
#include "utils/doctest/doctest_proxy.h"
#include "utils/types.h"
#include "utils/JsonData.h"
#include "utils/singleton.h"
#include "utils/transform.h"
#include "core/messages/message_macros.h"
#include "core/tags.h"
#include "core/Object.h"
#include "core/messages/messages_common.h"
#include "core/registry/registry.h"
The camera object can be accessed through the REPL by getting it through the executable interface and then interacting with it through the exported interfaces which it implements