Viktor Kirilov
C++ dev
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
By Viktor Kirilov
How to Make a Tiny, Embeddable and Powerful Interactive C++ Compiler (REPL)