Merge branch 'develop' into cleanups_and_reworkds

This commit is contained in:
Jason Turner 2016-06-29 16:11:00 -06:00
commit b0f07cbe5d
9 changed files with 230 additions and 18 deletions

28
DesignGoals.md Normal file
View 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)

View File

@ -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

View File

@ -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;

View File

@ -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 );
} }
} }

View File

@ -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

View File

@ -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");

View 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', '~')

View 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@")

View 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")