Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ if(BUILD_TESTING)
target_link_libraries(threading_config_test ${LIBS})
add_test(NAME Threading_Config_Test COMMAND threading_config_test)

add_executable(string_type_param_test unittests/string_type_param_test.cpp)
target_link_libraries(string_type_param_test ${LIBS})
add_test(NAME String_Type_Param_Test COMMAND string_type_param_test)

install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
endif()
endif()
Expand Down
12 changes: 8 additions & 4 deletions include/chaiscript/chaiscript.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,20 +820,24 @@
#include "language/chaiscript_parser.hpp"

namespace chaiscript {
class ChaiScript : public ChaiScript_Basic {
template<typename StringType>
class ChaiScript_Impl : public ChaiScript_Basic {
public:
ChaiScript(std::vector<std::string> t_modulepaths = {},
ChaiScript_Impl(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {},
std::vector<Options> t_opts = chaiscript::default_options(),
std::vector<Library_Options> t_lib_opts = {})
: ChaiScript_Basic(chaiscript::Std_Lib::library(t_lib_opts),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
: ChaiScript_Basic(chaiscript::Std_Lib::library<StringType>(t_lib_opts),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default, StringType>>(),
std::move(t_modulepaths),
std::move(t_usepaths),
std::move(t_opts),
std::find(t_lib_opts.begin(), t_lib_opts.end(), Library_Options::No_IO) != t_lib_opts.end()) {
}
};

using ChaiScript = ChaiScript_Impl<std::string>;
using ChaiScript_WString = ChaiScript_Impl<std::wstring>;
} // namespace chaiscript

#endif /* CHAISCRIPT_HPP_ */
4 changes: 2 additions & 2 deletions include/chaiscript/chaiscript_basic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
#include "language/chaiscript_parser.hpp"

ChaiScript_Basic chai(
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
chaiscript::Std_Lib::library<std::string>(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default, std::string>>());

*/

Expand Down
5 changes: 3 additions & 2 deletions include/chaiscript/chaiscript_stdlib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
namespace chaiscript {
class Std_Lib {
public:
template<typename StringType>
[[nodiscard]] static ModulePtr library(const std::vector<Library_Options> &t_opts = {}) {
if (std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Stdlib) != t_opts.end()) {
return std::make_shared<Module>();
Expand All @@ -49,10 +50,10 @@ namespace chaiscript {
const bool no_prelude = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Prelude) != t_opts.end();
const bool no_json = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_JSON) != t_opts.end();

bootstrap::Bootstrap::bootstrap(*lib, no_io);
bootstrap::Bootstrap::bootstrap<StringType>(*lib, no_io);

bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
bootstrap::standard_library::string_type<std::string>("string", *lib);
bootstrap::standard_library::string_type<StringType>("string", *lib);
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value>>("Map", *lib);
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value>>("Pair", *lib);

Expand Down
25 changes: 21 additions & 4 deletions include/chaiscript/dispatchkit/bootstrap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_

#include <type_traits>

#include "../utility/utility.hpp"
#include "register_function.hpp"

Expand Down Expand Up @@ -269,6 +271,7 @@ namespace chaiscript::bootstrap {
/// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to
/// \param[in] t_no_io If true, skip registering print_string and println_string
template<typename StringType>
static void bootstrap(Module &m, const bool t_no_io = false) {
m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool");
Expand Down Expand Up @@ -393,13 +396,27 @@ namespace chaiscript::bootstrap {
operators::equal<bool>(m);
operators::not_equal<bool>(m);

m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
m.add(fun([](const StringType &s) { return s; }), "to_string");
m.add(fun([](const bool b) -> StringType {
if constexpr (std::is_same_v<StringType, std::string>) {
return b ? "true" : "false";
} else {
const auto s = std::string(b ? "true" : "false");
return StringType(s.begin(), s.end());
}
}), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");

m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
m.add(fun([](const typename StringType::value_type c) -> StringType { return StringType(1, c); }), "to_string");
if constexpr (std::is_same_v<StringType, std::string>) {
m.add(fun(&Boxed_Number::to_string), "to_string");
} else {
m.add(fun([](const Boxed_Number &n) -> StringType {
const auto s = n.to_string();
return StringType(s.begin(), s.end());
}), "to_string");
}

bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
Expand Down
126 changes: 89 additions & 37 deletions include/chaiscript/language/chaiscript_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <memory>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>

#include "../dispatchkit/boxed_value.hpp"
Expand Down Expand Up @@ -101,9 +102,31 @@ namespace chaiscript {
return Char_Parser_Helper<std::true_type>::u8str_from_ll(val);
}
};
template<typename S>
int stoi_for_string(const S &s, std::size_t *pos, int base) {
if constexpr (std::is_same_v<S, std::string>) {
return std::stoi(s, pos, base);
} else if constexpr (std::is_same_v<S, std::wstring>) {
return std::stoi(std::wstring(s.begin(), s.end()), pos, base);
} else {
return std::stoi(std::string(s.begin(), s.end()), pos, base);
}
}

template<typename S>
long long stoll_for_string(const S &s, std::size_t *pos, int base) {
if constexpr (std::is_same_v<S, std::string>) {
return std::stoll(s, pos, base);
} else if constexpr (std::is_same_v<S, std::wstring>) {
return std::stoll(std::wstring(s.begin(), s.end()), pos, base);
} else {
return std::stoll(std::string(s.begin(), s.end()), pos, base);
}
}

} // namespace detail

template<typename Tracer, typename Optimizer, std::size_t Parse_Depth = 512>
template<typename Tracer, typename Optimizer, typename StringType, std::size_t Parse_Depth = 512>
class ChaiScript_Parser final : public ChaiScript_Parser_Base {
void *get_tracer_ptr() noexcept override { return &m_tracer; }

Expand Down Expand Up @@ -812,6 +835,17 @@ namespace chaiscript {
#endif
}

template<typename S>
static std::string to_narrow(const S &s) {
if constexpr (std::is_same_v<S, std::string>) {
return s;
} else if constexpr (std::is_convertible_v<S, std::string_view>) {
return std::string(s);
} else {
return std::string(s.begin(), s.end());
}
}

template<typename T, typename... Param>
std::unique_ptr<eval::AST_Node_Impl<Tracer>>
make_node(std::string_view t_match, const int t_prev_line, const int t_prev_col, Param &&...param) {
Expand Down Expand Up @@ -1100,8 +1134,8 @@ namespace chaiscript {

void process_hex() {
if (!hex_matches.empty()) {
auto val = stoll(hex_matches, nullptr, 16);
match.push_back(char_type(val));
const auto val = detail::stoll_for_string(hex_matches, nullptr, 16);
match.push_back(static_cast<char_type>(val));
}
hex_matches.clear();
is_escaped = false;
Expand All @@ -1110,50 +1144,67 @@ namespace chaiscript {

void process_octal() {
if (!octal_matches.empty()) {
auto val = stoll(octal_matches, nullptr, 8);
match.push_back(char_type(val));
const auto val = detail::stoll_for_string(octal_matches, nullptr, 8);
match.push_back(static_cast<char_type>(val));
}
octal_matches.clear();
is_escaped = false;
is_octal = false;
}

void process_unicode() {
const auto ch = static_cast<uint32_t>(std::stoi(hex_matches, nullptr, 16));
const auto ch = static_cast<uint32_t>(detail::stoi_for_string<string_type>(hex_matches, nullptr, 16));
const auto match_size = hex_matches.size();
hex_matches.clear();
is_escaped = false;
const auto u_size = unicode_size;
unicode_size = 0;

char buf[4];
if (u_size != match_size) {
throw exception::eval_error("Incomplete unicode escape sequence");
}
if (u_size == 4 && ch >= 0xD800 && ch <= 0xDFFF) {
throw exception::eval_error("Invalid 16 bit universal character");
}

if (ch < 0x80) {
match += static_cast<char>(ch);
} else if (ch < 0x800) {
buf[0] = static_cast<char>(0xC0 | (ch >> 6));
buf[1] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 2);
} else if (ch < 0x10000) {
buf[0] = static_cast<char>(0xE0 | (ch >> 12));
buf[1] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
buf[2] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 3);
} else if (ch < 0x200000) {
buf[0] = static_cast<char>(0xF0 | (ch >> 18));
buf[1] = static_cast<char>(0x80 | ((ch >> 12) & 0x3F));
buf[2] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
buf[3] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 4);
if constexpr (sizeof(char_type) >= 4) {
if (ch < 0x200000) {
match.push_back(static_cast<char_type>(ch));
} else {
throw exception::eval_error("Invalid 32 bit universal character");
}
} else if constexpr (sizeof(char_type) >= 2) {
if (ch < 0x10000) {
match.push_back(static_cast<char_type>(ch));
} else if (ch < 0x110000) {
const auto adjusted = ch - 0x10000;
match.push_back(static_cast<char_type>(0xD800 + (adjusted >> 10)));
match.push_back(static_cast<char_type>(0xDC00 + (adjusted & 0x3FF)));
} else {
throw exception::eval_error("Invalid 32 bit universal character");
}
} else {
// this must be an invalid escape sequence?
throw exception::eval_error("Invalid 32 bit universal character");
char buf[4];
if (ch < 0x80) {
match += static_cast<char>(ch);
} else if (ch < 0x800) {
buf[0] = static_cast<char>(0xC0 | (ch >> 6));
buf[1] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 2);
} else if (ch < 0x10000) {
buf[0] = static_cast<char>(0xE0 | (ch >> 12));
buf[1] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
buf[2] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 3);
} else if (ch < 0x200000) {
buf[0] = static_cast<char>(0xF0 | (ch >> 18));
buf[1] = static_cast<char>(0x80 | ((ch >> 12) & 0x3F));
buf[2] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
buf[3] = static_cast<char>(0x80 | (ch & 0x3F));
match.append(buf, 4);
} else {
throw exception::eval_error("Invalid 32 bit universal character");
}
}
}

Expand Down Expand Up @@ -1280,11 +1331,11 @@ namespace chaiscript {
const auto start = m_position;

if (Quoted_String_()) {
std::string match;
StringType match;
const auto prev_stack_top = m_match_stack.size();

bool is_interpolated = [&]() -> bool {
Char_Parser<std::string> cparser(match, true);
Char_Parser<StringType> cparser(match, true);

auto s = start + 1, end = m_position - 1;

Expand All @@ -1293,7 +1344,7 @@ namespace chaiscript {
if (*s == '{') {
// We've found an interpolation point

m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(to_narrow(match), start.line, start.col, const_var(match)));

if (cparser.is_interpolated) {
// If we've seen previous interpolation, add on instead of making a new one
Expand Down Expand Up @@ -1351,7 +1402,7 @@ namespace chaiscript {
return cparser.is_interpolated;
}();

m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(to_narrow(match), start.line, start.col, const_var(match)));

if (is_interpolated) {
build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
Expand Down Expand Up @@ -1439,7 +1490,7 @@ namespace chaiscript {
close_seq += '"';

// Extract raw content up to closing sequence
std::string match;
StringType match;
auto end = m_position; // m_position is already past the closing sequence

// Content is from s up to (end - close_seq.size())
Expand All @@ -1456,11 +1507,11 @@ namespace chaiscript {
break;
}
}
match.push_back(*s);
match.push_back(static_cast<typename StringType::value_type>(*s));
++s;
}

m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(to_narrow(match), start.line, start.col, const_var(match)));
return true;
}
return false;
Expand Down Expand Up @@ -1501,11 +1552,11 @@ namespace chaiscript {

const auto start = m_position;
if (Single_Quoted_String_()) {
std::string match;
StringType match;

{
// scope for cparser destructor
Char_Parser<std::string> cparser(match, false);
Char_Parser<StringType> cparser(match, false);

for (auto s = start + 1, end = m_position - 1; s != end; ++s) {
cparser.parse(*s, start.line, start.col, *m_filename);
Expand All @@ -1518,7 +1569,8 @@ namespace chaiscript {
*m_filename);
}

m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(char(match.at(0)))));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(to_narrow(match), start.line, start.col,
const_var(static_cast<typename StringType::value_type>(match.at(0)))));
return true;
} else {
return false;
Expand Down Expand Up @@ -2805,7 +2857,7 @@ namespace chaiscript {
}

AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override {
ChaiScript_Parser<Tracer, Optimizer> parser(m_tracer, m_optimizer);
ChaiScript_Parser<Tracer, Optimizer, StringType> parser(m_tracer, m_optimizer);
return parser.parse_internal(t_input, t_fname);
}

Expand Down
2 changes: 1 addition & 1 deletion src/chaiscript_stdlib_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#endif

CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib() {
return chaiscript::Std_Lib::library();
return chaiscript::Std_Lib::library<std::string>();
}

#ifdef __llvm__
Expand Down
2 changes: 1 addition & 1 deletion static_libs/chaiscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
#include "chaiscript_parser.hpp"

std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() {
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default, std::string>>();
}
2 changes: 1 addition & 1 deletion static_libs/chaiscript_stdlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
#include "chaiscript_stdlib.hpp"

std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() {
return chaiscript::Std_Lib::library();
return chaiscript::Std_Lib::library<std::string>();
}
Loading
Loading