diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 871b353b..647ed5b6 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -825,7 +825,7 @@ namespace chaiscript { ChaiScript(std::vector t_modulepaths = {}, std::vector t_usepaths = {}, std::vector t_opts = chaiscript::default_options()) - : ChaiScript_Basic(chaiscript::Std_Lib::library(), + : ChaiScript_Basic(chaiscript::Std_Lib::library(t_opts), std::make_unique>(), std::move(t_modulepaths), std::move(t_usepaths), diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index e01aadd3..fb07cf28 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -208,7 +208,11 @@ namespace chaiscript { No_Load_Modules, Load_Modules, No_External_Scripts, - External_Scripts + External_Scripts, + No_Stdlib, + No_IO, + No_Prelude, + No_JSON }; template diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 5cb4fa68..bcdc3165 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -38,9 +38,18 @@ namespace chaiscript { class Std_Lib { public: - [[nodiscard]] static ModulePtr library() { + [[nodiscard]] static ModulePtr library(const std::vector &t_opts = {}) { + if (std::find(t_opts.begin(), t_opts.end(), Options::No_Stdlib) != t_opts.end()) { + return std::make_shared(); + } + auto lib = std::make_shared(); - bootstrap::Bootstrap::bootstrap(*lib); + + const bool no_io = std::find(t_opts.begin(), t_opts.end(), Options::No_IO) != t_opts.end(); + const bool no_prelude = std::find(t_opts.begin(), t_opts.end(), Options::No_Prelude) != t_opts.end(); + const bool no_json = std::find(t_opts.begin(), t_opts.end(), Options::No_JSON) != t_opts.end(); + + bootstrap::Bootstrap::bootstrap(*lib, no_io); bootstrap::standard_library::vector_type>("Vector", *lib); bootstrap::standard_library::string_type("string", *lib); @@ -54,9 +63,13 @@ namespace chaiscript { "async"); #endif - json_wrap::library(*lib); + if (!no_json) { + json_wrap::library(*lib); + } - lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/); + if (!no_prelude) { + lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/); + } return lib; } diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index ba1de5ad..03ad1203 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -266,8 +266,8 @@ namespace chaiscript::bootstrap { public: /// \brief perform all common bootstrap functions for std::string, void and POD types /// \param[in,out] m Module to add bootstrapped functions to - /// \returns passed in Module - static void bootstrap(Module &m) { + /// \param[in] t_no_io If true, skip registering print_string and println_string + static void bootstrap(Module &m, const bool t_no_io = false) { m.add(user_type(), "void"); m.add(user_type(), "bool"); m.add(user_type(), "Object"); @@ -435,8 +435,10 @@ namespace chaiscript::bootstrap { m.add(fun(&Build_Info::compiler_id), "compiler_id"); m.add(fun(&Build_Info::debug_build), "debug_build"); - m.add(fun(&print), "print_string"); - m.add(fun(&println), "println_string"); + if (!t_no_io) { + m.add(fun(&print), "print_string"); + m.add(fun(&println), "println_string"); + } m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 1462c203..8cda152c 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -1283,3 +1283,93 @@ TEST_CASE("Test if non copyable/movable types can be registered") { chai.add(chaiscript::user_type(), "Nothing"); chai.add(chaiscript::constructor(), "Nothing"); } + +// Tests for issue #146: configuration to bypass registering built-in functions + +TEST_CASE("No_Stdlib option disables all standard library functions") { + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library({chaiscript::Options::No_Stdlib}), + create_chaiscript_parser(), + {}, + {}, + {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts}); + + // Core types should still work (they are part of bootstrap) + CHECK_NOTHROW(chai.eval("var x = 5")); + + // print should not exist + CHECK_THROWS(chai.eval("print(\"hello\")")); + + // Vector should not exist + CHECK_THROWS(chai.eval("var v = Vector()")); + + // String methods from prelude should not exist + CHECK_THROWS(chai.eval("\"hello\".trim()")); + + // JSON should not exist + CHECK_THROWS(chai.eval("from_json(\"[1,2,3]\")")); +} + +TEST_CASE("No_IO option disables print functions") { + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library({chaiscript::Options::No_IO}), + create_chaiscript_parser(), + {}, + {}, + {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts}); + + // print_string and println_string should not exist + CHECK_THROWS(chai.eval("print_string(\"hello\")")); + CHECK_THROWS(chai.eval("println_string(\"hello\")")); + + // Other functionality should still work + CHECK(chai.eval("5 + 3") == 8); + CHECK_NOTHROW(chai.eval("var v = Vector()")); +} + +TEST_CASE("No_Prelude option disables prelude functions") { + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library({chaiscript::Options::No_Prelude}), + create_chaiscript_parser(), + {}, + {}, + {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts}); + + // print (from prelude) should not exist + CHECK_THROWS(chai.eval("print(\"hello\")")); + + // But print_string (from bootstrap) should still work + CHECK_NOTHROW(chai.eval("print_string(\"hello\")")); + + // Prelude utility functions should not exist + CHECK_THROWS(chai.eval("filter([1,2,3], fun(x) { x > 1 })")); + + // Core arithmetic should still work + CHECK(chai.eval("5 + 3") == 8); +} + +TEST_CASE("No_JSON option disables JSON support") { + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library({chaiscript::Options::No_JSON}), + create_chaiscript_parser(), + {}, + {}, + {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts}); + + // JSON functions should not exist + CHECK_THROWS(chai.eval("from_json(\"[1,2,3]\")")); + + // Other functionality should still work + CHECK(chai.eval("5 + 3") == 8); + CHECK_NOTHROW(chai.eval("print(\"hello\")")); +} + +TEST_CASE("Default library has all functions") { + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library(), + create_chaiscript_parser(), + {}, + {}, + {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts}); + + // Everything should work with default options + CHECK_NOTHROW(chai.eval("print(\"hello\")")); + CHECK_NOTHROW(chai.eval("print_string(\"hello\")")); + CHECK_NOTHROW(chai.eval("var v = Vector()")); + CHECK(chai.eval("5 + 3") == 8); +}