Skip to content

Commit

Permalink
Polish repl server
Browse files Browse the repository at this point in the history
  • Loading branch information
bamboo committed Nov 23, 2024
1 parent bea7a3e commit 409c5df
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 82 deletions.
43 changes: 20 additions & 23 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import os
import sys
from methods import print_error

# -------------------------- Utility Functions --------------------------
def embed_file(target, source, env):
"""
Embeds the content of <source> file into a <target> header file as a const char* constant.
Expand Down Expand Up @@ -30,36 +31,32 @@ const char* {constant_name} = R"({file_content})";
#endif // {header_guard}
""")

def is_submodule_initialized(path):
return os.path.isdir(path) and os.listdir(path)

libname = "godot-s7-scheme"
projectdir = "demo"
# -------------------------- Build definition --------------------------

localEnv = Environment(tools=["default"], PLATFORM="")
lib_name = "godot-s7-scheme"
project_dir = "demo"

local_env = Environment(tools=["default"], PLATFORM="")

customs = ["custom.py"]
customs = [os.path.abspath(path) for path in customs]

opts = Variables(customs, ARGUMENTS)
opts.Update(localEnv)

Help(opts.GenerateHelpText(localEnv))

env = localEnv.Clone()
opts.Update(local_env)

submodule_initialized = False
dir_name = 'godot-cpp'
if os.path.isdir(dir_name):
if os.listdir(dir_name):
submodule_initialized = True
Help(opts.GenerateHelpText(local_env))

if not submodule_initialized:
if not is_submodule_initialized('godot-cpp'):
print_error("""godot-cpp is not available within this folder, as Git submodules haven't been initialized.
Run the following command to download godot-cpp:
git submodule update --init --recursive""")
sys.exit(1)

env = SConscript("godot-cpp/SConstruct", {"env": env, "customs": customs})
env = SConscript("godot-cpp/SConstruct", {"env": local_env.Clone(), "customs": customs})
env.Append(
CPPPATH=["src/", "s7/"],
CPPDEFINES={
Expand All @@ -84,23 +81,23 @@ if env["target"] in ["editor", "template_debug"]:
except AttributeError:
print("Not including class reference as we're targeting a pre-4.3 baseline.")

file = "{}{}{}".format(libname, env["suffix"], env["SHLIBSUFFIX"])
filepath = ""
file = "{}{}{}".format(lib_name, env["suffix"], env["SHLIBSUFFIX"])
file_path = ""

if env["platform"] == "macos" or env["platform"] == "ios":
filepath = "{}.framework/".format(env["platform"])
file = "{}.{}.{}".format(libname, env["platform"], env["target"])
file_path = "{}.framework/".format(env["platform"])
file = "{}.{}.{}".format(lib_name, env["platform"], env["target"])

libraryfile = "bin/{}/{}{}".format(env["platform"], filepath, file)
library_file = "bin/{}/{}{}".format(env["platform"], file_path, file)
library = env.SharedLibrary(
libraryfile,
library_file,
source=sources,
)

copy = env.InstallAs("{}/bin/{}/{}lib{}".format(projectdir, env["platform"], filepath, file), library)
copy = env.InstallAs("{}/bin/{}/{}lib{}".format(project_dir, env["platform"], file_path, file), library)

embed_scheme_repl = env.Command(
target="src/repl/s7_scheme_repl_string.hpp",
target="src/repl/generated/s7_scheme_repl_string.hpp",
source="demo/addons/s7/s7_scheme_repl.scm",
action=embed_file
)
Expand Down
119 changes: 60 additions & 59 deletions src/scheme_repl_server.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "scheme_repl_server.hpp"
#include "repl/s7_scheme_repl_string.hpp"
#include "repl/generated/s7_scheme_repl_string.hpp"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/stream_peer_tcp.hpp>
Expand All @@ -12,8 +12,6 @@
using namespace godot;
using gd = godot::UtilityFunctions;

typedef std::basic_string<char> str;

typedef std::pair<const char *, const char *> error_output_and_response;

template <typename T>
Expand All @@ -36,7 +34,7 @@ class ReplRequestCompiler {
~ReplRequestCompiler();

public:
error_output_and_response eval(const str &request);
error_output_and_response eval(const std::string &request);

private:
s7_protected_ptr compile_geiser_request;
Expand All @@ -47,9 +45,12 @@ ReplRequestCompiler::ReplRequestCompiler() {
compile_geiser_request = scheme.make_symbol("compile-geiser-request");
auto result = eval_with_error_output<const char *>(scheme.get(), [](auto sc) {
#if DEBUG_REPL_INTERACTIONS
std::cout << s7_scheme_repl_string << std::endl;
std::cout << s7_scheme_repl_string << std::endl;
#endif
return s7_object_to_c_string(sc, s7_load_c_string(sc, s7_scheme_repl_string, strlen(s7_scheme_repl_string)));
return s7_object_to_c_string(sc,
s7_load_c_string(sc,
s7_scheme_repl_string,
strlen(s7_scheme_repl_string)));
});
auto error_output = non_empty_nor_null(result.first);
if (error_output) {
Expand All @@ -61,7 +62,7 @@ ReplRequestCompiler::~ReplRequestCompiler() {
compile_geiser_request = nullptr;
}

error_output_and_response ReplRequestCompiler::eval(const str &request) {
error_output_and_response ReplRequestCompiler::eval(const std::string &request) {
auto compile_geiser_request = scheme.value_of(this->compile_geiser_request);
if (!s7_is_procedure(compile_geiser_request)) {
return std::make_pair(
Expand Down Expand Up @@ -119,14 +120,18 @@ class ReplClient {
tcp_stream(tcp_stream) {}

public:
void send(const CharString &s);
String get_prompt();
void send_prompt();
bool process(ReplRequestCompiler &compiler);
void disconnect();

private:
String get_prompt();
void send(const CharString &s);
bool process_buffer(ReplRequestCompiler &compiler);

private:
Ref<StreamPeerTCP> tcp_stream;
str buffer;
std::string buffer;
};

void ReplClient::disconnect() {
Expand All @@ -140,6 +145,10 @@ String ReplClient::get_prompt() {
return "\ns7@(:)> ";
}

void ReplClient::send_prompt() {
send(get_prompt().utf8());
}

bool ReplClient::process(ReplRequestCompiler &compiler) {
if (tcp_stream->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
return false;
Expand All @@ -155,85 +164,77 @@ bool ReplClient::process(ReplRequestCompiler &compiler) {
#endif

if (ch == '\n' && available == 0) {
auto prompt = get_prompt().utf8();
if (buffer == ",q") {
// disconnection from repl
if (!process_buffer(compiler)) {
return false;
}

auto result = compiler.eval(buffer);
buffer.clear();

if (result.first) {
gd::printerr(result.first);
send(result.first);
tcp_stream->put_8('\n');
}
gd::print(result.second);
send(result.second);
tcp_stream->put_8('\n');

send(prompt);
} else {
buffer.push_back(ch);
}
}
return tcp_stream->poll() == Error::OK;
}

bool ReplClient::process_buffer(ReplRequestCompiler &compiler) {
if (buffer == ",q") {
// disconnection from repl
return false;
}

auto result = compiler.eval(buffer);
buffer.clear();

if (result.first) {
gd::printerr(result.first);
send(result.first);
tcp_stream->put_8('\n');
}
#if DEBUG_REPL_INTERACTIONS
gd::print(result.second);
#endif
send(result.second);
tcp_stream->put_8('\n');

send_prompt();
return true;
}

void ReplClient::send(const CharString &s) {
for (int i = 0; i < s.length(); ++i) {
tcp_stream->put_8(s[i]);
}
}

class ReplController {
class ReplMediator {
public:
ReplController(Ref<TCPServer> server) :
ReplMediator(Ref<TCPServer> server) :
server(server) {}

public:
void process();
void mediate();

private:
Ref<TCPServer> server;
ReplRequestCompiler request_compiler;
std::vector<ReplClient> clients;
ReplRequestCompiler request_compiler;
};

void ReplController::process() {
void ReplMediator::mediate() {
if (server->is_connection_available()) {
// TODO: client starts with most recent Scheme node
auto client = ReplClient(server->take_connection());
gd::print("Scheme repl client connected.");
client.send(client.get_prompt().utf8());
client.send_prompt();
clients.emplace_back(std::move(client));
}

if (clients.empty()) {
return;
for (auto client = clients.begin(); client != clients.end();) {
if (!client->process(request_compiler)) {
client = clients.erase(client);
gd::print("Scheme repl client disconnected.");
} else {
client++;
}
}

auto client_index = 0;
auto disconnected = std::vector<int>();
std::for_each(
clients.begin(),
clients.end(),
[&](auto &client) {
if (!client.process(request_compiler)) {
disconnected.push_back(client_index);
}
client_index++;
});
std::for_each(
disconnected.rbegin(),
disconnected.rend(),
[&](auto i) {
auto c = clients.begin() + i;
c->disconnect();
clients.erase(c);
gd::print("Scheme repl client disconnected.");
});
}

void SchemeReplServer::server_loop() {
Expand All @@ -252,10 +253,10 @@ void SchemeReplServer::server_loop() {

gd::print("Scheme repl server listening on local port ", tcp_server->get_local_port());

auto controller = ReplController(tcp_server);
auto mediator = ReplMediator(tcp_server);
while (!exit_thread) {
controller.process();
OS::get_singleton()->delay_msec(250);
mediator.mediate();
OS::get_singleton()->delay_msec(50);
}
tcp_server->stop();
}
Expand Down

0 comments on commit 409c5df

Please sign in to comment.