mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Fix #116: Add set_file_reader callback for custom file loading
Add a customizable file reader callback to ChaiScript_Basic, following the same pattern as set_print_handler. When set, the callback is invoked instead of the default filesystem read, enabling use cases like encrypted files, in-memory virtual filesystems, or platform-specific file access (e.g., Android assets). The callback is settable from both C++ and ChaiScript. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
362e93fb29
commit
6beedc0787
@ -80,6 +80,7 @@ namespace chaiscript {
|
||||
std::map<std::string, std::function<Namespace &()>> m_namespace_generators;
|
||||
|
||||
std::function<void(const std::string &)> m_print_handler = [](const std::string &) noexcept {};
|
||||
std::function<std::string(const std::string &)> m_file_reader;
|
||||
|
||||
/// Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) {
|
||||
@ -139,6 +140,10 @@ namespace chaiscript {
|
||||
m_print_handler = t_handler;
|
||||
}), "set_print_handler");
|
||||
|
||||
m_engine.add(fun([this](const std::function<std::string(const std::string &)> &t_reader) {
|
||||
m_file_reader = t_reader;
|
||||
}), "set_file_reader");
|
||||
|
||||
m_engine.add(fun([this]() { m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv) { m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type) { return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
@ -236,7 +241,15 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
/// Helper function for loading a file
|
||||
static std::string load_file(const std::string &t_filename) {
|
||||
std::string load_file(const std::string &t_filename) const {
|
||||
if (m_file_reader) {
|
||||
return m_file_reader(t_filename);
|
||||
}
|
||||
|
||||
return load_file_default(t_filename);
|
||||
}
|
||||
|
||||
static std::string load_file_default(const std::string &t_filename) {
|
||||
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
|
||||
|
||||
if (!infile.is_open()) {
|
||||
@ -278,6 +291,12 @@ namespace chaiscript {
|
||||
m_print_handler = std::move(t_handler);
|
||||
}
|
||||
|
||||
/// \brief Set a custom handler for reading files, used by eval_file, use, and internal_eval_file
|
||||
/// \param[in] t_reader Function to call with the filename, returning the file contents as a string
|
||||
void set_file_reader(std::function<std::string(const std::string &)> t_reader) {
|
||||
m_file_reader = std::move(t_reader);
|
||||
}
|
||||
|
||||
/// \brief Virtual destructor for ChaiScript
|
||||
virtual ~ChaiScript_Basic() = default;
|
||||
|
||||
|
||||
@ -1782,3 +1782,42 @@ TEST_CASE("eval_error with AST_Node_Trace call stack compiles in C++20") {
|
||||
(void)stack;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test set_file_reader from C++ land") {
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.set_file_reader([](const std::string &) {
|
||||
return std::string("var file_reader_test_val = 42");
|
||||
});
|
||||
chai.eval_file("nonexistent_file.chai");
|
||||
CHECK(chai.eval<int>("file_reader_test_val") == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("Test set_file_reader from ChaiScript land") {
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.set_file_reader([](const std::string &) {
|
||||
return std::string("var from_custom_reader = true");
|
||||
});
|
||||
chai.eval("set_file_reader(fun(filename) { return \"var from_chai_reader = true\"; })");
|
||||
chai.eval_file("any_file.chai");
|
||||
CHECK(chai.eval<bool>("from_chai_reader") == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Test set_file_reader receives correct filename") {
|
||||
chaiscript::ChaiScript chai;
|
||||
std::string captured_filename;
|
||||
chai.set_file_reader([&captured_filename](const std::string &t_filename) {
|
||||
captured_filename = t_filename;
|
||||
return std::string("var dummy = 1");
|
||||
});
|
||||
chai.eval_file("my_special_file.chai");
|
||||
CHECK(captured_filename == "my_special_file.chai");
|
||||
}
|
||||
|
||||
TEST_CASE("Test use with set_file_reader") {
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.set_file_reader([](const std::string &) {
|
||||
return std::string("var use_reader_val = 99");
|
||||
});
|
||||
chai.use("virtual_file.chai");
|
||||
CHECK(chai.eval<int>("use_reader_val") == 99);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user