mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 16:57:04 +08:00
Merge branch 'develop' into cleanups_and_reworkds
This commit is contained in:
commit
b0f07cbe5d
28
DesignGoals.md
Normal file
28
DesignGoals.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
|
||||||
|
|
||||||
|
# Goals
|
||||||
|
|
||||||
|
1. Trivially easy to integrate with C++ projects
|
||||||
|
2. 0 external depenencies
|
||||||
|
3. "Perfect" integration with C++
|
||||||
|
* Direct mapping between ChaiScript objects and C++ objects
|
||||||
|
* Direct mapping between ChaiScript functions and C++ functions
|
||||||
|
* Direct mapping between ChaiScript exceptions and C++ exceptions
|
||||||
|
3. Never surprise the C++ developer
|
||||||
|
* Object lifetimes managed by the stack
|
||||||
|
* Familiar syntax to C++ developers
|
||||||
|
4. Perform "well enough" to not get in the way
|
||||||
|
|
||||||
|
|
||||||
|
# Alternatives
|
||||||
|
|
||||||
|
## Sol2
|
||||||
|
|
||||||
|
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
|
||||||
|
|
||||||
|
## SWIG
|
||||||
|
|
||||||
|
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)
|
||||||
|
|
||||||
@ -60,6 +60,10 @@
|
|||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
|
||||||
|
#define CHAISCRIPT_UTF16_UTF32
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define CHAISCRIPT_DEBUG true
|
#define CHAISCRIPT_DEBUG true
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -16,6 +16,11 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(CHAISCRIPT_UTF16_UTF32)
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "../dispatchkit/boxed_value.hpp"
|
#include "../dispatchkit/boxed_value.hpp"
|
||||||
@ -56,6 +61,53 @@ namespace chaiscript
|
|||||||
, max_alphabet
|
, max_alphabet
|
||||||
, lengthof_alphabet = 256
|
, lengthof_alphabet = 256
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Generic for u16, u32 and wchar
|
||||||
|
template<typename string_type>
|
||||||
|
struct Char_Parser_Helper
|
||||||
|
{
|
||||||
|
// common for all implementations
|
||||||
|
static std::string u8str_from_ll(long long val)
|
||||||
|
{
|
||||||
|
typedef std::string::value_type char_type;
|
||||||
|
|
||||||
|
char_type c[2];
|
||||||
|
c[1] = char_type(val);
|
||||||
|
c[0] = char_type(val >> 8);
|
||||||
|
|
||||||
|
if (c[0] == 0)
|
||||||
|
{
|
||||||
|
return std::string(1, c[1]); // size, character
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(c, 2); // char buffer, size
|
||||||
|
}
|
||||||
|
|
||||||
|
static string_type str_from_ll(long long val)
|
||||||
|
{
|
||||||
|
typedef typename string_type::value_type target_char_type;
|
||||||
|
#if defined (CHAISCRIPT_UTF16_UTF32)
|
||||||
|
// prepare converter
|
||||||
|
std::wstring_convert<std::codecvt_utf8<target_char_type>, target_char_type> converter;
|
||||||
|
// convert
|
||||||
|
return converter.from_bytes(u8str_from_ll(val));
|
||||||
|
#else
|
||||||
|
// no conversion available, just put value as character
|
||||||
|
return string_type(1, target_char_type(val)); // size, character
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for char AKA UTF-8
|
||||||
|
template<>
|
||||||
|
struct Char_Parser_Helper<std::string>
|
||||||
|
{
|
||||||
|
static std::string str_from_ll(long long val)
|
||||||
|
{
|
||||||
|
// little SFINAE trick to avoid base class
|
||||||
|
return Char_Parser_Helper<std::true_type>::u8str_from_ll(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -880,6 +932,7 @@ namespace chaiscript
|
|||||||
bool saw_interpolation_marker = false;
|
bool saw_interpolation_marker = false;
|
||||||
bool is_octal = false;
|
bool is_octal = false;
|
||||||
bool is_hex = false;
|
bool is_hex = false;
|
||||||
|
bool is_unicode = false;
|
||||||
const bool interpolation_allowed;
|
const bool interpolation_allowed;
|
||||||
|
|
||||||
string_type octal_matches;
|
string_type octal_matches;
|
||||||
@ -901,6 +954,10 @@ namespace chaiscript
|
|||||||
if (is_hex) {
|
if (is_hex) {
|
||||||
process_hex();
|
process_hex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_unicode) {
|
||||||
|
process_unicode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_hex()
|
void process_hex()
|
||||||
@ -922,9 +979,23 @@ namespace chaiscript
|
|||||||
is_octal = false;
|
is_octal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void process_unicode()
|
||||||
|
{
|
||||||
|
auto val = stoll(hex_matches, 0, 16);
|
||||||
|
hex_matches.clear();
|
||||||
|
match += detail::Char_Parser_Helper<string_type>::str_from_ll(val);
|
||||||
|
is_escaped = false;
|
||||||
|
is_unicode = false;
|
||||||
|
}
|
||||||
|
|
||||||
void parse(const char_type t_char, const int line, const int col, const std::string &filename) {
|
void parse(const char_type t_char, const int line, const int col, const std::string &filename) {
|
||||||
const bool is_octal_char = t_char >= '0' && t_char <= '7';
|
const bool is_octal_char = t_char >= '0' && t_char <= '7';
|
||||||
|
|
||||||
|
const bool is_hex_char = (t_char >= '0' && t_char <= '9')
|
||||||
|
|| (t_char >= 'a' && t_char <= 'f')
|
||||||
|
|| (t_char >= 'A' && t_char <= 'F');
|
||||||
|
|
||||||
if (is_octal) {
|
if (is_octal) {
|
||||||
if (is_octal_char) {
|
if (is_octal_char) {
|
||||||
octal_matches.push_back(t_char);
|
octal_matches.push_back(t_char);
|
||||||
@ -937,10 +1008,6 @@ namespace chaiscript
|
|||||||
process_octal();
|
process_octal();
|
||||||
}
|
}
|
||||||
} else if (is_hex) {
|
} else if (is_hex) {
|
||||||
const bool is_hex_char = (t_char >= '0' && t_char <= '9')
|
|
||||||
|| (t_char >= 'a' && t_char <= 'f')
|
|
||||||
|| (t_char >= 'A' && t_char <= 'F');
|
|
||||||
|
|
||||||
if (is_hex_char) {
|
if (is_hex_char) {
|
||||||
hex_matches.push_back(t_char);
|
hex_matches.push_back(t_char);
|
||||||
|
|
||||||
@ -955,6 +1022,21 @@ namespace chaiscript
|
|||||||
} else {
|
} else {
|
||||||
process_hex();
|
process_hex();
|
||||||
}
|
}
|
||||||
|
} else if (is_unicode) {
|
||||||
|
if (is_hex_char) {
|
||||||
|
hex_matches.push_back(t_char);
|
||||||
|
|
||||||
|
if(hex_matches.size() == 4) {
|
||||||
|
// Format is specified to be 'slash'uABCD
|
||||||
|
// on collecting from A to D do parsing
|
||||||
|
process_unicode();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Not a unicode anymore, try parsing any way
|
||||||
|
// May be someone used 'slash'uAA only
|
||||||
|
process_unicode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_char == '\\') {
|
if (t_char == '\\') {
|
||||||
@ -971,6 +1053,8 @@ namespace chaiscript
|
|||||||
octal_matches.push_back(t_char);
|
octal_matches.push_back(t_char);
|
||||||
} else if (t_char == 'x') {
|
} else if (t_char == 'x') {
|
||||||
is_hex = true;
|
is_hex = true;
|
||||||
|
} else if (t_char == 'u') {
|
||||||
|
is_unicode = true;
|
||||||
} else {
|
} else {
|
||||||
switch (t_char) {
|
switch (t_char) {
|
||||||
case ('\'') : match.push_back('\''); break;
|
case ('\'') : match.push_back('\''); break;
|
||||||
|
|||||||
@ -47,6 +47,79 @@ class JSON
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
struct QuickFlatMap
|
||||||
|
{
|
||||||
|
auto find(const std::string &s) {
|
||||||
|
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto find(const std::string &s) const {
|
||||||
|
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto size() const {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto begin() const {
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end() const {
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto begin() {
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end() {
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSON &operator[](const std::string &s) {
|
||||||
|
const auto itr = find(s);
|
||||||
|
if (itr != data.end()) {
|
||||||
|
return itr->second;
|
||||||
|
} else {
|
||||||
|
data.emplace_back(s, JSON());
|
||||||
|
return data.back().second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON &at(const std::string &s) {
|
||||||
|
const auto itr = find(s);
|
||||||
|
if (itr != data.end()) {
|
||||||
|
return itr->second;
|
||||||
|
} else {
|
||||||
|
throw std::out_of_range("Unknown key: " + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSON &at(const std::string &s) const {
|
||||||
|
const auto itr = find(s);
|
||||||
|
if (itr != data.end()) {
|
||||||
|
return itr->second;
|
||||||
|
} else {
|
||||||
|
throw std::out_of_range("Unknown key: " + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count(const std::string &s) const {
|
||||||
|
return (find(s) != data.end())?1:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, JSON>> data;
|
||||||
|
|
||||||
|
using iterator = decltype(data)::iterator;
|
||||||
|
using const_iterator = decltype(data)::const_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct Internal {
|
struct Internal {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto clone(const std::unique_ptr<T> &ptr) {
|
auto clone(const std::unique_ptr<T> &ptr) {
|
||||||
@ -100,7 +173,7 @@ class JSON
|
|||||||
String.reset();
|
String.reset();
|
||||||
|
|
||||||
switch( type ) {
|
switch( type ) {
|
||||||
case Class::Object: Map = std::make_unique<std::map<std::string,JSON>>(); break;
|
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
|
||||||
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
|
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
|
||||||
case Class::String: String = std::make_unique<std::string>(); break;
|
case Class::String: String = std::make_unique<std::string>(); break;
|
||||||
case Class::Floating: Float = 0.0; break;
|
case Class::Floating: Float = 0.0; break;
|
||||||
@ -116,7 +189,7 @@ class JSON
|
|||||||
Internal &operator=(Internal &&) = default;
|
Internal &operator=(Internal &&) = default;
|
||||||
|
|
||||||
std::unique_ptr<std::vector<JSON>> List;
|
std::unique_ptr<std::vector<JSON>> List;
|
||||||
std::unique_ptr<std::map<std::string,JSON>> Map;
|
std::unique_ptr<QuickFlatMap> Map;
|
||||||
std::unique_ptr<std::string> String;
|
std::unique_ptr<std::string> String;
|
||||||
double Float = 0;
|
double Float = 0;
|
||||||
long Int = 0;
|
long Int = 0;
|
||||||
@ -229,7 +302,7 @@ class JSON
|
|||||||
|
|
||||||
bool has_key( const std::string &key ) const {
|
bool has_key( const std::string &key ) const {
|
||||||
if( internal.Type == Class::Object ) {
|
if( internal.Type == Class::Object ) {
|
||||||
return internal.Map->find( key ) != internal.Map->end();
|
return internal.Map->count(key) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -274,11 +347,11 @@ class JSON
|
|||||||
return ok ? internal.Bool : false;
|
return ok ? internal.Bool : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONWrapper<std::map<std::string,JSON>> object_range() {
|
JSONWrapper<QuickFlatMap> object_range() {
|
||||||
if( internal.Type == Class::Object ) {
|
if( internal.Type == Class::Object ) {
|
||||||
return JSONWrapper<std::map<std::string,JSON>>( internal.Map.get() );
|
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
|
||||||
} else {
|
} else {
|
||||||
return JSONWrapper<std::map<std::string,JSON>>( nullptr );
|
return JSONWrapper<QuickFlatMap>( nullptr );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,11 +363,11 @@ class JSON
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONConstWrapper<std::map<std::string,JSON>> object_range() const {
|
JSONConstWrapper<QuickFlatMap> object_range() const {
|
||||||
if( internal.Type == Class::Object ) {
|
if( internal.Type == Class::Object ) {
|
||||||
return JSONConstWrapper<std::map<std::string,JSON>>( internal.Map.get() );
|
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
|
||||||
} else {
|
} else {
|
||||||
return JSONConstWrapper<std::map<std::string,JSON>>( nullptr );
|
return JSONConstWrapper<QuickFlatMap>( nullptr );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,10 +43,9 @@ languages:
|
|||||||
Requirements
|
Requirements
|
||||||
============
|
============
|
||||||
|
|
||||||
ChaiScript requires a C++11 compiler to build with support for variadic
|
ChaiScript requires a C++14 compiler to build with support for variadic
|
||||||
templates. It has been tested with gcc 4.6 and clang 3.1 (with libcxx). MacOS
|
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
|
||||||
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
|
For more information see the build
|
||||||
clang 4.0. MSVC 2013 or newer is supports also. For more information see the build
|
|
||||||
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
|
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
|
|||||||
@ -73,7 +73,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
|
|
||||||
//Create a new system object and share it with the chaiscript engine
|
//Create a new system object and share it with the chaiscript engine
|
||||||
System system;
|
System system;
|
||||||
chai.add(var(&system), "system");
|
chai.add_global(var(&system), "system");
|
||||||
|
|
||||||
//Add a bound callback method
|
//Add a bound callback method
|
||||||
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
|
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
|
||||||
|
|||||||
8
unittests/string_unicode_ascii.chai
Normal file
8
unittests/string_unicode_ascii.chai
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
assert_equal('\u0020', ' ')
|
||||||
|
assert_equal('\u0021', '!')
|
||||||
|
assert_equal('\u0030', '0')
|
||||||
|
assert_equal('\u0040', '@')
|
||||||
|
assert_equal('\u005B', '[')
|
||||||
|
assert_equal('\u005d', ']')
|
||||||
|
assert_equal('\u0061', 'a')
|
||||||
|
assert_equal('\u007e', '~')
|
||||||
11
unittests/string_unicode_parse.chai
Normal file
11
unittests/string_unicode_parse.chai
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
assert_equal('\u00aa', '\u00AA')
|
||||||
|
assert_equal('\u00bb', '\uBB')
|
||||||
|
assert_equal('\ucc', '\u00CC')
|
||||||
|
assert_equal('\udd', '\uDD')
|
||||||
|
|
||||||
|
assert_equal('\u0ee', '\uEE')
|
||||||
|
assert_equal('\ue', '\u000E')
|
||||||
|
|
||||||
|
assert_equal("\u30\u31\u32", "012")
|
||||||
|
assert_equal("\u33Test", "3Test")
|
||||||
|
assert_equal("Test\u0040", "Test@")
|
||||||
5
unittests/string_unicode_unicode.chai
Normal file
5
unittests/string_unicode_unicode.chai
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
assert_equal("\uc39c", "Ü")
|
||||||
|
assert_equal("U for \uc39cmlauts", "U for Ümlauts")
|
||||||
|
assert_equal("More \uc39cml\uc3a4\uc3bcts", "More Ümläüts")
|
||||||
|
|
||||||
|
assert_equal("Thorn \uc3be sign", "Thorn þ sign")
|
||||||
Loading…
x
Reference in New Issue
Block a user