Merge branch 'develop' into typed_function_ordering

This commit is contained in:
Jason Turner 2016-12-05 19:19:41 -07:00
commit 93bc6109e7
34 changed files with 645 additions and 465 deletions

View File

@ -92,6 +92,7 @@ chai.add(chaiscript::user_type<MyClass>(), "MyClass");
User defined type conversions are possible, defined in either script or in C++. User defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions ### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions Function objects (including lambdas) can be used to add type conversions
@ -115,6 +116,21 @@ Calling a user defined type conversion that takes a lambda
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ })); chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
``` ```
### Class Hierarchies
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
```
chai.add(chaiscript::base_class<Base, Derived>());
```
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
```
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
```
### Helpers ### Helpers
@ -206,7 +222,7 @@ Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you
```cpp ```cpp
// ok this is supported, you can register it with chaiscript engine // ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) { void nullify_shared_ptr(std::shared_ptr<int> &t) {
t == nullptr t = nullptr
} }
``` ```
@ -313,6 +329,15 @@ while (some_condition()) { /* do something */ }
for (x : [1,2,3]) { print(i); } for (x : [1,2,3]) { print(i); }
``` ```
Each of the loop styles can be broken using the `break` statement. For example:
```
while (some_condition()) {
/* do something */
if (another_condition()) { break; }
}
```
## Conditionals ## Conditionals
``` ```

View File

@ -65,7 +65,7 @@
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(&function, "function"); /// chai.add(chaiscript::fun(&function), "function");
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }

View File

@ -72,7 +72,7 @@ namespace chaiscript {
{ {
} }
virtual void *data() override void *data() override
{ {
return &m_data; return &m_data;
} }

View File

@ -31,12 +31,12 @@ namespace chaiscript
public: public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept std::string t_what) noexcept
: from(std::move(t_from)), to(&t_to), m_what(std::move(t_what)) : from(t_from), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
{ {
} }
@ -46,10 +46,10 @@ namespace chaiscript
} }
bad_boxed_cast(const bad_boxed_cast &) = default; bad_boxed_cast(const bad_boxed_cast &) = default;
virtual ~bad_boxed_cast() noexcept = default; ~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred /// \brief Description of what error occurred
virtual const char * what() const noexcept override const char * what() const noexcept override
{ {
return m_what.c_str(); return m_what.c_str();
} }

View File

@ -37,7 +37,7 @@ namespace chaiscript
/// Bidir_Range, based on the D concept of ranges. /// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on /// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in /// the user_typetraits of the iterator passed in
template<typename Container> template<typename Container, typename IterType>
struct Bidir_Range struct Bidir_Range
{ {
typedef Container container_type; typedef Container container_type;
@ -79,64 +79,6 @@ namespace chaiscript
return (*m_begin); return (*m_begin);
} }
decltype(auto) back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::iterator pos = m_end;
--pos;
return (*(pos));
}
typename Container::iterator m_begin;
typename Container::iterator m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
decltype(auto) front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return (*m_begin);
}
decltype(auto) back() const decltype(auto) back() const
{ {
if (empty()) if (empty())
@ -148,8 +90,8 @@ namespace chaiscript
return (*(pos)); return (*(pos));
} }
typename Container::const_iterator m_begin; IterType m_begin;
typename Container::const_iterator m_end; IterType m_end;
}; };
namespace detail { namespace detail {
@ -229,8 +171,8 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
void input_range_type(const std::string &type, Module& m) void input_range_type(const std::string &type, Module& m)
{ {
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m); detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m);
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m); detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
} }
template<typename ContainerType> template<typename ContainerType>
ModulePtr input_range_type(const std::string &type) ModulePtr input_range_type(const std::string &type)

View File

@ -25,7 +25,7 @@ namespace chaiscript
template<typename T> template<typename T>
T* throw_if_null(T *t) T* throw_if_null(T *t)
{ {
if (t) return t; if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value"); throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
@ -135,6 +135,39 @@ namespace chaiscript
} }
}; };
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&>
{
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&>
{
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<std::shared_ptr<Result> >

View File

@ -28,9 +28,9 @@ namespace chaiscript
{ {
struct arithmetic_error : std::runtime_error struct arithmetic_error : std::runtime_error
{ {
arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
arithmetic_error(const arithmetic_error &) = default; arithmetic_error(const arithmetic_error &) = default;
virtual ~arithmetic_error() noexcept = default; ~arithmetic_error() noexcept override = default;
}; };
} }
} }

View File

@ -54,7 +54,7 @@ namespace chaiscript
if (rhs.m_attrs) if (rhs.m_attrs)
{ {
m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs)); m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
} }
return *this; return *this;
@ -119,6 +119,8 @@ namespace chaiscript
); );
} }
template<typename T> template<typename T>
static auto get(T *t, bool t_return_value) static auto get(T *t, bool t_return_value)
{ {
@ -145,6 +147,19 @@ namespace chaiscript
); );
} }
template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
false,
ptr,
t_return_value
);
}
template<typename T> template<typename T>
static auto get(T t, bool t_return_value) static auto get(T t, bool t_return_value)
{ {
@ -302,7 +317,7 @@ namespace chaiscript
{ {
if (!m_data->m_attrs) if (!m_data->m_attrs)
{ {
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>()); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
} }
auto &attr = (*m_data->m_attrs)[t_name]; auto &attr = (*m_data->m_attrs)[t_name];
@ -319,7 +334,7 @@ namespace chaiscript
{ {
if (t_obj.m_data->m_attrs) if (t_obj.m_data->m_attrs)
{ {
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs)); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
} }
return *this; return *this;
} }
@ -342,8 +357,8 @@ namespace chaiscript
// necessary to avoid hitting the templated && constructor of Boxed_Value // necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{}; struct Internal_Construction{};
Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction) Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(t_data) { : m_data(std::move(t_data)) {
} }
std::shared_ptr<Data> m_data = Object_Data::get(); std::shared_ptr<Data> m_data = Object_Data::get();

View File

@ -25,7 +25,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Const_Caller struct Const_Caller
{ {
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const { Ret operator()(const Class &o, Inner&& ... inner) const {
@ -38,7 +38,7 @@ namespace chaiscript {
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Fun_Caller struct Fun_Caller
{ {
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Inner&& ... inner) const { Ret operator()(Inner&& ... inner) const {
@ -51,7 +51,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Caller struct Caller
{ {
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Class &o, Inner&& ... inner) const { Ret operator()(Class &o, Inner&& ... inner) const {

View File

@ -67,7 +67,7 @@ namespace chaiscript
reserved_word_error(const reserved_word_error &) = default; reserved_word_error(const reserved_word_error &) = default;
virtual ~reserved_word_error() noexcept = default; ~reserved_word_error() noexcept override = default;
std::string word() const std::string word() const
{ {
@ -89,7 +89,7 @@ namespace chaiscript
illegal_name_error(const illegal_name_error &) = default; illegal_name_error(const illegal_name_error &) = default;
virtual ~illegal_name_error() noexcept = default; ~illegal_name_error() noexcept override = default;
std::string name() const std::string name() const
{ {
@ -112,7 +112,7 @@ namespace chaiscript
name_conflict_error(const name_conflict_error &) = default; name_conflict_error(const name_conflict_error &) = default;
virtual ~name_conflict_error() noexcept = default; ~name_conflict_error() noexcept override = default;
std::string name() const std::string name() const
{ {
@ -135,7 +135,7 @@ namespace chaiscript
} }
global_non_const(const global_non_const &) = default; global_non_const(const global_non_const &) = default;
virtual ~global_non_const() noexcept = default; ~global_non_const() noexcept override = default;
}; };
} }
@ -147,7 +147,7 @@ namespace chaiscript
public: public:
Module &add(Type_Info ti, std::string name) Module &add(Type_Info ti, std::string name)
{ {
m_typeinfos.emplace_back(std::move(ti), std::move(name)); m_typeinfos.emplace_back(ti, std::move(name));
return *this; return *this;
} }
@ -266,7 +266,7 @@ namespace chaiscript
class Dispatch_Function final : public dispatch::Proxy_Function_Base class Dispatch_Function final : public dispatch::Proxy_Function_Base
{ {
public: public:
Dispatch_Function(std::vector<Proxy_Function> t_funcs) explicit Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
m_funcs(std::move(t_funcs)) m_funcs(std::move(t_funcs))
{ {
@ -356,7 +356,7 @@ namespace chaiscript
++begin; ++begin;
} }
assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken");
if (size_mismatch) if (size_mismatch)
{ {
@ -447,7 +447,7 @@ namespace chaiscript
Type_Name_Map m_types; Type_Name_Map m_types;
}; };
Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser)
: m_stack_holder(this), : m_stack_holder(this),
m_parser(parser) m_parser(parser)
{ {
@ -681,7 +681,7 @@ namespace chaiscript
} }
t_loc = static_cast<uint_fast32_t>(Loc::located); t_loc = static_cast<uint_fast32_t>(Loc::located);
} else if (loc & static_cast<uint_fast32_t>(Loc::is_local)) { } else if ((loc & static_cast<uint_fast32_t>(Loc::is_local)) != 0u) {
auto &stack = get_stack_data(t_holder); auto &stack = get_stack_data(t_holder);
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second; return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
@ -698,9 +698,9 @@ namespace chaiscript
// no? is it a function object? // no? is it a function object?
auto obj = get_function_object_int(name, loc); auto obj = get_function_object_int(name, loc);
if (obj.first != loc) t_loc = uint_fast32_t(obj.first); if (obj.first != loc) { t_loc = uint_fast32_t(obj.first); }
return obj.second;
return obj.second;
} }
@ -763,7 +763,10 @@ namespace chaiscript
{ {
uint_fast32_t method_missing_loc = m_method_missing_loc; uint_fast32_t method_missing_loc = m_method_missing_loc;
auto method_missing_funs = get_function("method_missing", method_missing_loc); auto method_missing_funs = get_function("method_missing", method_missing_loc);
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc = uint_fast32_t(method_missing_funs.first); if (method_missing_funs.first != method_missing_loc) {
m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
}
return std::move(method_missing_funs.second); return std::move(method_missing_funs.second);
} }
@ -954,7 +957,7 @@ namespace chaiscript
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc;
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc = uint_fast32_t(funs.first); if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); }
const auto do_attribute_call = const auto do_attribute_call =
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value [this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
@ -1074,7 +1077,8 @@ namespace chaiscript
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc;
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc = uint_fast32_t(funs.first); if (funs.first != loc) { t_loc = uint_fast32_t(funs.first);
}
return dispatch::dispatch(*funs.second, params, t_conversions); return dispatch::dispatch(*funs.second, params, t_conversions);
} }
@ -1206,7 +1210,7 @@ namespace chaiscript
static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params) static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params)); t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params);
} }
static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params) static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
@ -1224,7 +1228,7 @@ namespace chaiscript
void save_function_params(std::initializer_list<Boxed_Value> t_params) void save_function_params(std::initializer_list<Boxed_Value> t_params)
{ {
save_function_params(*m_stack_holder, std::move(t_params)); save_function_params(*m_stack_holder, t_params);
} }
void save_function_params(std::vector<Boxed_Value> &&t_params) void save_function_params(std::vector<Boxed_Value> &&t_params)
@ -1588,7 +1592,7 @@ namespace chaiscript
class Dispatch_State class Dispatch_State
{ {
public: public:
Dispatch_State(Dispatch_Engine &t_engine) explicit Dispatch_State(Dispatch_Engine &t_engine)
: m_engine(t_engine), : m_engine(t_engine),
m_stack_holder(t_engine.get_stack_holder()), m_stack_holder(t_engine.get_stack_holder()),
m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves())

View File

@ -25,7 +25,7 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
option_explicit_set(const std::string &t_param_name) explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{ {
@ -33,13 +33,13 @@ namespace chaiscript
option_explicit_set(const option_explicit_set &) = default; option_explicit_set(const option_explicit_set &) = default;
virtual ~option_explicit_set() noexcept = default; ~option_explicit_set() noexcept override = default;
}; };
class Dynamic_Object class Dynamic_Object
{ {
public: public:
Dynamic_Object(std::string t_type_name) explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(std::move(t_type_name)), m_option_explicit(false)
{ {
} }

View File

@ -110,7 +110,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@ -120,7 +120,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@ -162,7 +162,7 @@ namespace chaiscript
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{ {
if (bvs.size() > 0) if (!bvs.empty())
{ {
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else { } else {
@ -226,7 +226,7 @@ namespace chaiscript
bool operator==(const Proxy_Function_Base &f) const override bool operator==(const Proxy_Function_Base &f) const override
{ {
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f); const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override

View File

@ -33,7 +33,7 @@ namespace chaiscript
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
} else { } else {
Type_Conversions conv; Type_Conversions conv;
@ -52,7 +52,7 @@ namespace chaiscript
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>(); return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
} else { } else {
Type_Conversions conv; Type_Conversions conv;
@ -72,7 +72,7 @@ namespace chaiscript
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
dispatch::dispatch(t_funcs, params, *t_conversions); dispatch::dispatch(t_funcs, params, *t_conversions);
} else { } else {
Type_Conversions conv; Type_Conversions conv;

View File

@ -53,14 +53,14 @@ namespace chaiscript
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
{} {}
Param_Types(const std::vector<Type_Info> &t_types) explicit Param_Types(const std::vector<Type_Info> &t_types)
: m_types(build_param_types(t_types)), : m_types(build_param_types(t_types)),
m_has_types(false), m_has_types(false),
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
{ {
} }
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types) explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types)), : m_types(std::move(t_types)),
m_has_types(false), m_has_types(false),
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
@ -82,7 +82,7 @@ namespace chaiscript
void push_front(std::string t_name, Type_Info t_ti) void push_front(std::string t_name, Type_Info t_ti)
{ {
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti)); m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
update_has_types(); update_has_types();
} }
@ -93,8 +93,8 @@ namespace chaiscript
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{ {
if (!m_has_types) return true; if (!m_has_types) { return true; }
if (vals.size() != m_types.size()) return false; if (vals.size() != m_types.size()) { return false; }
for (size_t i = 0; i < vals.size(); ++i) for (size_t i = 0; i < vals.size(); ++i)
{ {
@ -301,7 +301,7 @@ namespace chaiscript
guard_error(const guard_error &) = default; guard_error(const guard_error &) = default;
virtual ~guard_error() noexcept = default; ~guard_error() noexcept override = default;
}; };
} }
@ -333,18 +333,18 @@ namespace chaiscript
} }
virtual bool operator==(const Proxy_Function_Base &rhs) const override bool operator==(const Proxy_Function_Base &rhs) const override
{ {
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs); const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
return this == &rhs return this == &rhs
|| (prhs || ((prhs != nullptr)
&& this->m_arity == prhs->m_arity && this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard && !this->m_guard && !prhs->m_guard
&& this->m_param_types == prhs->m_param_types); && this->m_param_types == prhs->m_param_types);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{ {
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
&& test_guard(vals, t_conversions); && test_guard(vals, t_conversions);
@ -547,7 +547,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@ -560,7 +560,7 @@ namespace chaiscript
class Proxy_Function_Impl_Base : public Proxy_Function_Base class Proxy_Function_Impl_Base : public Proxy_Function_Base
{ {
public: public:
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types) explicit Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1) : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{ {
} }
@ -581,7 +581,7 @@ namespace chaiscript
class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base
{ {
public: public:
Proxy_Function_Callable_Impl(Callable f) explicit Proxy_Function_Callable_Impl(Callable f)
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))), : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(std::move(f)) m_f(std::move(f))
{ {
@ -612,7 +612,7 @@ namespace chaiscript
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
{ {
public: public:
Assignable_Proxy_Function(const std::vector<Type_Info> &t_types) explicit Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
: Proxy_Function_Impl_Base(t_types) : Proxy_Function_Impl_Base(t_types)
{ {
} }
@ -668,7 +668,7 @@ namespace chaiscript
class Attribute_Access final : public Proxy_Function_Base class Attribute_Access final : public Proxy_Function_Base
{ {
public: public:
Attribute_Access(T Class::* t_attr) explicit Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types(), 1), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
@ -773,7 +773,7 @@ namespace chaiscript
dispatch_error(const dispatch_error &) = default; dispatch_error(const dispatch_error &) = default;
virtual ~dispatch_error() noexcept = default; ~dispatch_error() noexcept override = default;
std::vector<Boxed_Value> parameters; std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions; std::vector<Const_Proxy_Function> functions;
@ -790,7 +790,7 @@ namespace chaiscript
{ {
const std::vector<Type_Info> &types = t_func->get_param_types(); const std::vector<Type_Info> &types = t_func->get_param_types();
if (t_func->get_arity() == -1) return false; if (t_func->get_arity() == -1) { return false; }
assert(plist.size() == types.size() - 1); assert(plist.size() == types.size() - 1);

View File

@ -44,7 +44,7 @@ namespace chaiscript
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
virtual ~arity_error() noexcept {} ~arity_error() noexcept override = default;
int got; int got;
int expected; int expected;

View File

@ -84,12 +84,14 @@ arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p)) if (pointer_in_buffer(p))
{ {
n = align_up(n); n = align_up(n);
if (p + n == ptr_) if (p + n == ptr_) {
ptr_ = p; ptr_ = p;
}
}
else {
::operator delete(p);
} }
else
::operator delete(p);
} }
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)> template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
@ -108,13 +110,13 @@ public:
short_alloc(const short_alloc&) = default; short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete; short_alloc& operator=(const short_alloc&) = delete;
short_alloc(arena_type& a) noexcept : a_(a) explicit short_alloc(arena_type& a) noexcept : a_(a)
{ {
static_assert(size % alignment == 0, static_assert(size % alignment == 0,
"size N needs to be a multiple of alignment Align"); "size N needs to be a multiple of alignment Align");
} }
template <class U> template <class U>
short_alloc(const short_alloc<U, N, alignment>& a) noexcept explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
: a_(a.a_) {} : a_(a.a_) {}
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;}; template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};

View File

@ -39,14 +39,14 @@ namespace chaiscript
{ {
} }
bad_boxed_dynamic_cast(const std::string &w) noexcept explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
virtual ~bad_boxed_dynamic_cast() noexcept = default; ~bad_boxed_dynamic_cast() noexcept override = default;
}; };
class bad_boxed_type_cast : public bad_boxed_cast class bad_boxed_type_cast : public bad_boxed_cast
@ -63,14 +63,14 @@ namespace chaiscript
{ {
} }
bad_boxed_type_cast(const std::string &w) noexcept explicit bad_boxed_type_cast(const std::string &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_type_cast(const bad_boxed_type_cast &) = default; bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
virtual ~bad_boxed_type_cast() noexcept = default; ~bad_boxed_type_cast() noexcept override = default;
}; };
} }
@ -100,8 +100,8 @@ namespace chaiscript
virtual ~Type_Conversion_Base() = default; virtual ~Type_Conversion_Base() = default;
protected: protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(t_to), m_from(t_from) : m_to(std::move(t_to)), m_from(std::move(t_from))
{ {
} }
@ -286,7 +286,7 @@ namespace chaiscript
{ {
public: public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)), : Type_Conversion_Base(t_to, t_from),
m_func(std::move(t_func)) m_func(std::move(t_func))
{ {
} }
@ -302,7 +302,7 @@ namespace chaiscript
return m_func(t_from); return m_func(t_from);
} }
virtual bool bidir() const override bool bidir() const override
{ {
return false; return false;
} }
@ -399,7 +399,7 @@ namespace chaiscript
{ {
try { try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from); Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (t_saves.enabled) t_saves.saves.push_back(ret); if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
@ -413,7 +413,7 @@ namespace chaiscript
{ {
try { try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to); Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (t_saves.enabled) t_saves.saves.push_back(ret); if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");

View File

@ -7,6 +7,8 @@
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/fnv1a.hpp"
#include <string> #include <string>
namespace chaiscript namespace chaiscript
@ -51,76 +53,39 @@ namespace chaiscript
static Opers to_operator(const std::string &t_str, bool t_is_unary = false) static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{ {
if (t_str == "==") const auto op_hash = utility::fnv1a_32(t_str.c_str());
{ switch (op_hash) {
return Opers::equals; case utility::fnv1a_32("=="): { return Opers::equals; }
} else if (t_str == "<") { case utility::fnv1a_32("<"): { return Opers::less_than; }
return Opers::less_than; case utility::fnv1a_32(">"): { return Opers::greater_than; }
} else if (t_str == ">") { case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
return Opers::greater_than; case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
} else if (t_str == "<=") { case utility::fnv1a_32("!="): { return Opers::not_equal; }
return Opers::less_than_equal; case utility::fnv1a_32("="): { return Opers::assign; }
} else if (t_str == ">=") { case utility::fnv1a_32("++"): { return Opers::pre_increment; }
return Opers::greater_than_equal; case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
} else if (t_str == "!=") { case utility::fnv1a_32("*="): { return Opers::assign_product; }
return Opers::not_equal; case utility::fnv1a_32("+="): { return Opers::assign_sum; }
} else if (t_str == "=") { case utility::fnv1a_32("-="): { return Opers::assign_difference; }
return Opers::assign; case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
} else if (t_str == "++") { case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
return Opers::pre_increment; case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
} else if (t_str == "--") { case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
return Opers::pre_decrement; case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
} else if (t_str == "*=") { case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
return Opers::assign_product; case utility::fnv1a_32("<<"): { return Opers::shift_left; }
} else if (t_str == "+=") { case utility::fnv1a_32(">>"): { return Opers::shift_right; }
return Opers::assign_sum; case utility::fnv1a_32("%"): { return Opers::remainder; }
} else if (t_str == "-=") { case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
return Opers::assign_difference; case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
} else if (t_str == "&=") { case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
return Opers::assign_bitwise_and; case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
} else if (t_str == "|=") { case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
return Opers::assign_bitwise_or; case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
} else if (t_str == "<<=") { case utility::fnv1a_32("/"): { return Opers::quotient; }
return Opers::assign_shift_left; case utility::fnv1a_32("*"): { return Opers::product; }
} else if (t_str == ">>=") { default: { return Opers::invalid; }
return Opers::assign_shift_right; }
} else if (t_str == "%=") {
return Opers::assign_remainder;
} else if (t_str == "^=") {
return Opers::assign_bitwise_xor;
} else if (t_str == "<<") {
return Opers::shift_left;
} else if (t_str == ">>") {
return Opers::shift_right;
} else if (t_str == "%") {
return Opers::remainder;
} else if (t_str == "&") {
return Opers::bitwise_and;
} else if (t_str == "|") {
return Opers::bitwise_or;
} else if (t_str == "^") {
return Opers::bitwise_xor;
} else if (t_str == "~") {
return Opers::bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return Opers::unary_plus;
} else {
return Opers::sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return Opers::unary_minus;
} else {
return Opers::difference;
}
} else if (t_str == "/") {
return Opers::quotient;
} else if (t_str == "*") {
return Opers::product;
} else {
return Opers::invalid;
}
} }
}; };

View File

@ -62,7 +62,7 @@ namespace chaiscript
Array_Call, Dot_Access, Array_Call, Dot_Access,
Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Try, Catch, Finally, Method, Attr_Decl, Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
}; };
enum class Operator_Precidence { Ternary_Cond, Logical_Or, enum class Operator_Precidence { Ternary_Cond, Logical_Or,
@ -72,7 +72,7 @@ namespace chaiscript
namespace namespace
{ {
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
const char *ast_node_type_to_string(AST_Node_Type ast_node_type) { inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
"Array_Call", "Dot_Access", "Array_Call", "Dot_Access",
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
@ -130,7 +130,7 @@ namespace chaiscript
/// \brief Thrown if an error occurs while attempting to load a binary module /// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error struct load_module_error : std::runtime_error
{ {
load_module_error(const std::string &t_reason) noexcept explicit load_module_error(const std::string &t_reason) noexcept
: std::runtime_error(t_reason) : std::runtime_error(t_reason)
{ {
} }
@ -141,7 +141,7 @@ namespace chaiscript
} }
load_module_error(const load_module_error &) = default; load_module_error(const load_module_error &) = default;
virtual ~load_module_error() noexcept = default; ~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
{ {
@ -188,7 +188,7 @@ namespace chaiscript
reason(t_why), start_position(t_where), filename(t_fname) reason(t_why), start_position(t_where), filename(t_fname)
{} {}
eval_error(const std::string &t_why) noexcept explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why) reason(t_why)
{} {}
@ -200,7 +200,7 @@ namespace chaiscript
std::ostringstream ss; std::ostringstream ss;
ss << what(); ss << what();
if (call_stack.size() > 0) { if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n'; ss << '\n' << detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
@ -217,7 +217,7 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
virtual ~eval_error() noexcept = default; ~eval_error() noexcept override = default;
private: private:
@ -476,12 +476,12 @@ namespace chaiscript
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
file_not_found_error(const std::string &t_filename) noexcept explicit file_not_found_error(const std::string &t_filename) noexcept
: std::runtime_error("File Not Found: " + t_filename) : std::runtime_error("File Not Found: " + t_filename)
{ } { }
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
virtual ~file_not_found_error() noexcept {} ~file_not_found_error() noexcept override = default;
}; };
} }
@ -597,19 +597,19 @@ namespace chaiscript
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { } explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
Break_Loop() { } Break_Loop() = default;
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
Continue_Loop() { } Continue_Loop() = default;
}; };
@ -621,7 +621,7 @@ namespace chaiscript
Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_scope(m_ds.stack_holder()); m_ds->new_scope(m_ds.stack_holder());
@ -645,7 +645,7 @@ namespace chaiscript
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
@ -663,7 +663,7 @@ namespace chaiscript
void save_params(std::initializer_list<Boxed_Value> t_params) void save_params(std::initializer_list<Boxed_Value> t_params)
{ {
m_ds->save_function_params(std::move(t_params)); m_ds->save_function_params(t_params);
} }
@ -679,7 +679,7 @@ namespace chaiscript
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_stack(m_ds.stack_holder()); m_ds->new_stack(m_ds.stack_holder());

View File

@ -79,7 +79,7 @@ namespace chaiscript
{ {
try { try {
const auto p = m_parser->parse(t_input, t_filename); const auto p = m_parser->parse(t_input, t_filename);
return p->eval(m_engine); return p->eval(chaiscript::detail::Dispatch_State(m_engine));
} }
catch (chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
@ -255,7 +255,7 @@ namespace chaiscript
memset( &rInfo, 0, sizeof(rInfo) ); memset( &rInfo, 0, sizeof(rInfo) );
cast_union u; cast_union u;
u.in_ptr = &ChaiScript_Basic::use; u.in_ptr = &ChaiScript_Basic::use;
if ( dladdr(static_cast<void*>(u.out_ptr), &rInfo) && rInfo.dli_fname ) { if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
@ -284,7 +284,7 @@ namespace chaiscript
/// ///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser, explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {}, std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {}, std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
@ -307,11 +307,15 @@ namespace chaiscript
} }
} }
parser::ChaiScript_Parser_Base &get_parser()
{
return *m_parser;
}
const Boxed_Value eval(const AST_NodePtr &t_ast) const Boxed_Value eval(const AST_NodePtr &t_ast)
{ {
try { try {
return t_ast->eval(m_engine); return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) { } catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee); throw Boxed_Value(t_ee);
} }

View File

@ -64,7 +64,7 @@ namespace chaiscript
}(); }();
chaiscript::eval::detail::Stack_Push_Pop tpp(state); chaiscript::eval::detail::Stack_Push_Pop tpp(state);
if (thisobj) state.add_object("this", *thisobj); if (thisobj) { state.add_object("this", *thisobj); }
if (t_locals) { if (t_locals) {
for (const auto &local : *t_locals) { for (const auto &local : *t_locals) {
@ -91,11 +91,16 @@ namespace chaiscript
{ {
AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc,
std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>()) std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
: AST_Node(std::move(t_ast_node_text), std::move(t_id), std::move(t_loc)), : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)),
children(std::move(t_children)) children(std::move(t_children))
{ {
} }
static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
return get_bool_condition(node.eval(t_ss), t_ss);
}
std::vector<AST_NodePtr> get_children() const final { std::vector<AST_NodePtr> get_children() const final {
return {children.begin(), children.end()}; return {children.begin(), children.end()};
@ -238,7 +243,7 @@ namespace chaiscript
{ {
} }
Constant_AST_Node(Boxed_Value t_value) explicit Constant_AST_Node(Boxed_Value t_value)
: AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()), : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()),
m_value(std::move(t_value)) m_value(std::move(t_value))
{ {
@ -270,60 +275,13 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc = {0}; mutable std::atomic_uint_fast32_t m_loc = {0};
}; };
template<typename T> template<typename T>
struct Unused_Return_Fun_Call_AST_Node final : AST_Node_Impl<T> { struct Fun_Call_AST_Node : AST_Node_Impl<T> {
Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Unused_Return_Fun_Call, std::move(t_loc), std::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params;
params.reserve(this->children[1]->children.size());
for (const auto &child : this->children[1]->children) {
params.push_back(child->eval(t_ss));
}
Boxed_Value fn(this->children[0]->eval(t_ss));
try {
return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(params, t_ss.conversions());
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
}
catch(const exception::bad_boxed_cast &){
try {
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
// handle the case where there is only 1 function to try to call and dispatch fails on it
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
};
template<typename T>
struct Fun_Call_AST_Node final : AST_Node_Impl<T> {
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { } AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override template<bool Save_Params>
Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
{ {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
@ -334,7 +292,9 @@ namespace chaiscript
params.push_back(child->eval(t_ss)); params.push_back(child->eval(t_ss));
} }
fpp.save_params(params); if (Save_Params) {
fpp.save_params(params);
}
Boxed_Value fn(this->children[0]->eval(t_ss)); Boxed_Value fn(this->children[0]->eval(t_ss));
@ -364,10 +324,28 @@ namespace chaiscript
} }
} }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
return do_eval_internal<true>(t_ss);
}
}; };
template<typename T>
struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> {
Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
Fun_Call_AST_Node<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
return this->template do_eval_internal<false>(t_ss);
}
};
template<typename T> template<typename T>
struct Arg_AST_Node final : AST_Node_Impl<T> { struct Arg_AST_Node final : AST_Node_Impl<T> {
@ -773,7 +751,7 @@ namespace chaiscript
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try { try {
while (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
try { try {
this->children[1]->eval(t_ss); this->children[1]->eval(t_ss);
} catch (detail::Continue_Loop &) { } catch (detail::Continue_Loop &) {
@ -808,21 +786,6 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Ternary_Cond_AST_Node final : AST_Node_Impl<T> {
Ternary_Cond_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ternary_Cond, std::move(t_loc), std::move(t_children))
{ assert(this->children.size() == 3); }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
return this->children[1]->eval(t_ss);
} else {
return this->children[2]->eval(t_ss);
}
}
};
template<typename T> template<typename T>
struct If_AST_Node final : AST_Node_Impl<T> { struct If_AST_Node final : AST_Node_Impl<T> {
@ -851,7 +814,7 @@ namespace chaiscript
const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
uint_fast32_t hint = t_hint; uint_fast32_t hint = t_hint;
auto funs = t_ss->get_function(t_name, hint); auto funs = t_ss->get_function(t_name, hint);
if (funs.first != hint) t_hint = uint_fast32_t(funs.first); if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); }
return std::move(funs.second); return std::move(funs.second);
}; };
@ -931,7 +894,7 @@ namespace chaiscript
try { try {
for ( for (
this->children[0]->eval(t_ss); this->children[0]->eval(t_ss);
this->get_bool_condition(this->children[1]->eval(t_ss), t_ss); this->get_scoped_bool_condition(*this->children[1], t_ss);
this->children[2]->eval(t_ss) this->children[2]->eval(t_ss)
) { ) {
try { try {
@ -1311,11 +1274,8 @@ namespace chaiscript
try { try {
retval = this->children[0]->eval(t_ss); retval = this->children[0]->eval(t_ss);
} }
catch (exception::eval_error &) { catch (const exception::eval_error &e) {
if (this->children.back()->identifier == AST_Node_Type::Finally) { retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
this->children.back()->children[0]->eval(t_ss);
}
throw;
} }
catch (const std::runtime_error &e) { catch (const std::runtime_error &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));

View File

@ -17,7 +17,7 @@ namespace chaiscript {
struct Optimizer : T... struct Optimizer : T...
{ {
Optimizer() = default; Optimizer() = default;
Optimizer(T ... t) explicit Optimizer(T ... t)
: T(std::move(t))... : T(std::move(t))...
{ {
} }
@ -165,7 +165,7 @@ namespace chaiscript {
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) { auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::Block if ((node->identifier == AST_Node_Type::Block
|| node->identifier == AST_Node_Type::Scopeless_Block) || node->identifier == AST_Node_Type::Scopeless_Block)
&& node->children.size() > 0) && !node->children.empty())
{ {
for (size_t i = 0; i < node->children.size()-1; ++i) { for (size_t i = 0; i < node->children.size()-1; ++i) {
auto child = node->children[i]; auto child = node->children[i];
@ -196,7 +196,7 @@ namespace chaiscript {
struct If { struct If {
template<typename T> template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) { auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::If || node->identifier == AST_Node_Type::Ternary_Cond) if ((node->identifier == AST_Node_Type::If)
&& node->children.size() >= 2 && node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant) && node->children[0]->identifier == AST_Node_Type::Constant)
{ {

View File

@ -23,6 +23,8 @@
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
#include "chaiscript_optimizer.hpp" #include "chaiscript_optimizer.hpp"
#include "chaiscript_tracer.hpp" #include "chaiscript_tracer.hpp"
#include "../utility/fnv1a.hpp"
#include "../utility/static_string.hpp"
#if defined(CHAISCRIPT_UTF16_UTF32) #if defined(CHAISCRIPT_UTF16_UTF32)
#include <locale> #include <locale>
@ -186,8 +188,8 @@ namespace chaiscript
} }
static const std::vector<std::vector<std::string>> &create_operator_matches() { static const std::vector<std::vector<utility::Static_String>> &create_operator_matches() {
static const std::vector<std::vector<std::string>> operator_matches { static const std::vector<std::vector<utility::Static_String>> operator_matches {
{"?"}, {"?"},
{"||"}, {"||"},
{"&&"}, {"&&"},
@ -225,13 +227,38 @@ namespace chaiscript
return operators; return operators;
} }
static constexpr const char * const m_multiline_comment_begin = "/*"; static const utility::Static_String &multiline_comment_end()
static constexpr const char * const m_multiline_comment_end = "*/"; {
static constexpr const char * const m_singleline_comment = "//"; static const utility::Static_String s("*/");
static constexpr const char * const m_annotation = "#"; return s;
}
static const utility::Static_String &multiline_comment_begin()
{
static const utility::Static_String s("/*");
return s;
}
static const utility::Static_String &singleline_comment()
{
static const utility::Static_String s("//");
return s;
}
static const utility::Static_String &annotation()
{
static const utility::Static_String s("#");
return s;
}
static const utility::Static_String &cr_lf()
{
static const utility::Static_String s("\r\n");
return s;
}
const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &m_alphabet = create_alphabet(); const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &m_alphabet = create_alphabet();
const std::vector<std::vector<std::string>> &m_operator_matches = create_operator_matches(); const std::vector<std::vector<utility::Static_String>> &m_operator_matches = create_operator_matches();
const std::array<Operator_Precidence, 12> &m_operators = create_operators(); const std::array<Operator_Precidence, 12> &m_operators = create_operators();
std::shared_ptr<std::string> m_filename; std::shared_ptr<std::string> m_filename;
@ -243,7 +270,7 @@ namespace chaiscript
Position() = default; Position() = default;
Position(std::string::const_iterator t_pos, std::string::const_iterator t_end) Position(std::string::const_iterator t_pos, std::string::const_iterator t_end)
: line(1), col(1), m_pos(std::move(t_pos)), m_end(std::move(t_end)), m_last_col(1) : line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1)
{ {
} }
@ -318,9 +345,10 @@ namespace chaiscript
return static_cast<size_t>(std::distance(m_pos, m_end)); return static_cast<size_t>(std::distance(m_pos, m_end));
} }
char operator*() const { const char& operator*() const {
if (m_pos == m_end) { if (m_pos == m_end) {
return '\0'; static const char ktmp ='\0';
return ktmp;
} else { } else {
return *m_pos; return *m_pos;
} }
@ -355,6 +383,16 @@ namespace chaiscript
m_match_stack.reserve(2); m_match_stack.reserve(2);
} }
Tracer &get_tracer()
{
return m_tracer;
}
Optimizer &get_optimizer()
{
return m_optimizer;
}
ChaiScript_Parser(const ChaiScript_Parser &) = default; ChaiScript_Parser(const ChaiScript_Parser &) = default;
ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete; ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete;
ChaiScript_Parser(ChaiScript_Parser &&) = default; ChaiScript_Parser(ChaiScript_Parser &&) = default;
@ -418,20 +456,36 @@ namespace chaiscript
} }
/// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace
inline auto Symbol_(const utility::Static_String &sym)
{
const auto len = sym.size();
if (m_position.remaining() >= len) {
const char *file_pos = &(*m_position);
for (size_t pos = 0; pos < len; ++pos)
{
if (sym.c_str()[pos] != file_pos[pos]) { return false; }
}
m_position += len;
return true;
}
return false;
}
/// Skips any multi-line or single-line comment /// Skips any multi-line or single-line comment
bool SkipComment() { bool SkipComment() {
if (Symbol_(m_multiline_comment_begin)) { if (Symbol_(multiline_comment_begin())) {
while (m_position.has_more()) { while (m_position.has_more()) {
if (Symbol_(m_multiline_comment_end)) { if (Symbol_(multiline_comment_end())) {
break; break;
} else if (!Eol_()) { } else if (!Eol_()) {
++m_position; ++m_position;
} }
} }
return true; return true;
} else if (Symbol_(m_singleline_comment)) { } else if (Symbol_(singleline_comment())) {
while (m_position.has_more()) { while (m_position.has_more()) {
if (Symbol_("\r\n")) { if (Symbol_(cr_lf())) {
m_position -= 2; m_position -= 2;
break; break;
} else if (Char_('\n')) { } else if (Char_('\n')) {
@ -442,9 +496,9 @@ namespace chaiscript
} }
} }
return true; return true;
} else if (Symbol_(m_annotation)) { } else if (Symbol_(annotation())) {
while (m_position.has_more()) { while (m_position.has_more()) {
if (Symbol_("\r\n")) { if (Symbol_(cr_lf())) {
m_position -= 2; m_position -= 2;
break; break;
} else if (Char_('\n')) { } else if (Char_('\n')) {
@ -823,74 +877,77 @@ namespace chaiscript
const auto start = m_position; const auto start = m_position;
if (Id_()) { if (Id_()) {
const auto text = Position::str(start, m_position); auto text = Position::str(start, m_position);
const auto text_hash = utility::fnv1a_32(text.c_str());
if (validate) { if (validate) {
validate_object_name(text); validate_object_name(text);
} }
if (text == "true") { switch (text_hash) {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(true))); case utility::fnv1a_32("true"): {
} else if (text == "false") { m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(true)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(false))); } break;
} else if (text == "Infinity") { case utility::fnv1a_32("false"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(false)));
const_var(std::numeric_limits<double>::infinity()))); } break;
} else if (text == "NaN") { case utility::fnv1a_32("Infinity"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const_var(std::numeric_limits<double>::quiet_NaN()))); const_var(std::numeric_limits<double>::infinity())));
} else if (text == "__LINE__") { } break;
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, case utility::fnv1a_32("NaN"): {
const_var(start.line))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
} else if (text == "__FILE__") { const_var(std::numeric_limits<double>::quiet_NaN())));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, } break;
const_var(m_filename))); case utility::fnv1a_32("__LINE__"): {
} else if (text == "__FUNC__") { m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const std::string fun_name = [&]()->std::string{ const_var(start.line)));
} break;
case utility::fnv1a_32("__FILE__"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const_var(m_filename)));
} break;
case utility::fnv1a_32("__FUNC__"): {
std::string fun_name = "NOT_IN_FUNCTION";
for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx) for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx)
{ {
if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
return m_match_stack[idx-1]->text; fun_name = m_match_stack[idx-1]->text;
} }
} }
return "NOT_IN_FUNCTION";
}();
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const_var(std::move(fun_name)))); const_var(fun_name)));
} else if (text == "__CLASS__") { } break;
const std::string fun_name = [&]()->std::string{ case utility::fnv1a_32("__CLASS__"): {
std::string fun_name = "NOT_IN_CLASS";
for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx) for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx)
{ {
if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
&& m_match_stack[idx-1]->identifier == AST_Node_Type::Id && m_match_stack[idx-1]->identifier == AST_Node_Type::Id
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
return m_match_stack[idx-2]->text; fun_name = m_match_stack[idx-2]->text;
} }
} }
return "NOT_IN_CLASS";
}();
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const_var(std::move(fun_name)))); const_var(fun_name)));
} else if (text == "_") { } break;
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, case utility::fnv1a_32("_"): {
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>()))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
} else { Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>( } break;
[&]()->std::string{ default: {
if (*start == '`') { std::string val = std::move(text);
// 'escaped' literal, like an operator name if (*start == '`') {
return Position::str(start+1, m_position-1); // 'escaped' literal, like an operator name
} else { val = Position::str(start+1, m_position-1);
return text; }
} m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(val, start.line, start.col));
}(), } break;
start.line, start.col));
} }
return true; return true;
} else { } else {
return false; return false;
@ -999,7 +1056,7 @@ namespace chaiscript
void process_hex() void process_hex()
{ {
auto val = stoll(hex_matches, 0, 16); auto val = stoll(hex_matches, nullptr, 16);
match.push_back(char_type(val)); match.push_back(char_type(val));
hex_matches.clear(); hex_matches.clear();
is_escaped = false; is_escaped = false;
@ -1009,7 +1066,7 @@ namespace chaiscript
void process_octal() void process_octal()
{ {
auto val = stoll(octal_matches, 0, 8); auto val = stoll(octal_matches, nullptr, 8);
match.push_back(char_type(val)); match.push_back(char_type(val));
octal_matches.clear(); octal_matches.clear();
is_escaped = false; is_escaped = false;
@ -1019,7 +1076,7 @@ namespace chaiscript
void process_unicode() void process_unicode()
{ {
auto val = stoll(hex_matches, 0, 16); auto val = stoll(hex_matches, nullptr, 16);
hex_matches.clear(); hex_matches.clear();
match += detail::Char_Parser_Helper<string_type>::str_from_ll(val); match += detail::Char_Parser_Helper<string_type>::str_from_ll(val);
is_escaped = false; is_escaped = false;
@ -1288,13 +1345,12 @@ namespace chaiscript
} }
/// Reads a string from input if it matches the parameter, without skipping initial whitespace /// Reads a string from input if it matches the parameter, without skipping initial whitespace
bool Keyword_(const char *t_s) { bool Keyword_(const utility::Static_String &t_s) {
const auto len = strlen(t_s); const auto len = t_s.size();
if (m_position.remaining() >= len) { if (m_position.remaining() >= len) {
auto tmp = m_position; auto tmp = m_position;
for (size_t i = 0; tmp.has_more() && i < len; ++i) { for (size_t i = 0; tmp.has_more() && i < len; ++i) {
if (*tmp != t_s[i]) { if (*tmp != t_s.c_str()[i]) {
return false; return false;
} }
++tmp; ++tmp;
@ -1307,7 +1363,7 @@ namespace chaiscript
} }
/// Reads (and potentially captures) a string from input if it matches the parameter /// Reads (and potentially captures) a string from input if it matches the parameter
bool Keyword(const char *t_s) { bool Keyword(const utility::Static_String &t_s) {
SkipWS(); SkipWS();
const auto start = m_position; const auto start = m_position;
bool retval = Keyword_(t_s); bool retval = Keyword_(t_s);
@ -1320,37 +1376,18 @@ namespace chaiscript
return retval; return retval;
} }
/// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace
bool Symbol_(const char *t_s) {
const auto len = strlen(t_s);
if (m_position.remaining() >= len) {
auto tmp = m_position;
for (size_t i = 0; m_position.has_more() && i < len; ++i) {
if (*tmp != t_s[i]) {
return false;
}
++tmp;
}
m_position = tmp;
return true;
}
return false;
}
bool is_operator(const std::string &t_s) const { bool is_operator(const std::string &t_s) const {
return std::any_of(m_operator_matches.begin(), m_operator_matches.end(), return std::any_of(m_operator_matches.begin(), m_operator_matches.end(),
[t_s](const std::vector<std::string> &opers) { [t_s](const std::vector<utility::Static_String> &opers) {
return std::any_of(opers.begin(), opers.end(), return std::any_of(opers.begin(), opers.end(),
[t_s](const std::string &s) { [t_s](const utility::Static_String &s) {
return s == t_s; return t_s == s.c_str();
}); });
}); });
} }
/// Reads (and potentially captures) a symbol group from input if it matches the parameter /// Reads (and potentially captures) a symbol group from input if it matches the parameter
bool Symbol(const char *t_s, const bool t_disallow_prevention=false) { bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention=false) {
SkipWS(); SkipWS();
const auto start = m_position; const auto start = m_position;
bool retval = Symbol_(t_s); bool retval = Symbol_(t_s);
@ -1372,7 +1409,7 @@ namespace chaiscript
bool Eol_(const bool t_eos = false) { bool Eol_(const bool t_eos = false) {
bool retval = false; bool retval = false;
if (m_position.has_more() && (Symbol_("\r\n") || Char_('\n'))) { if (m_position.has_more() && (Symbol_(cr_lf()) || Char_('\n'))) {
retval = true; retval = true;
//++m_position.line; //++m_position.line;
m_position.col = 1; m_position.col = 1;
@ -1735,12 +1772,16 @@ namespace chaiscript
} }
/// Reads a class block from input /// Reads a class block from input
bool Class() { bool Class(const bool t_class_allowed) {
bool retval = false; bool retval = false;
size_t prev_stack_top = m_match_stack.size(); size_t prev_stack_top = m_match_stack.size();
if (Keyword("class")) { if (Keyword("class")) {
if (!t_class_allowed) {
throw exception::eval_error("Class definitions only allowed at top scope", File_Position(m_position.line, m_position.col), *m_filename);
}
retval = true; retval = true;
if (!Id(true)) { if (!Id(true)) {
@ -2058,17 +2099,21 @@ namespace chaiscript
/// \todo Work around for method calls until we have a better solution /// \todo Work around for method calls until we have a better solution
if (!m_match_stack.back()->children.empty()) { if (!m_match_stack.back()->children.empty()) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) {
if (m_match_stack.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (m_match_stack.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); }
if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
}
auto dot_access = m_match_stack.back()->children[0]; auto dot_access = m_match_stack.back()->children[0];
auto func_call = m_match_stack.back(); auto func_call = m_match_stack.back();
m_match_stack.pop_back(); m_match_stack.pop_back();
func_call->children.erase(func_call->children.begin()); func_call->children.erase(func_call->children.begin());
if (dot_access->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
}
func_call->children.insert(func_call->children.begin(), dot_access->children.back()); func_call->children.insert(func_call->children.begin(), dot_access->children.back());
dot_access->children.pop_back(); dot_access->children.pop_back();
dot_access->children.push_back(std::move(func_call)); dot_access->children.push_back(std::move(func_call));
if (dot_access->children.size() != 2) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
}
m_match_stack.push_back(std::move(dot_access)); m_match_stack.push_back(std::move(dot_access));
} }
} }
@ -2178,7 +2223,7 @@ namespace chaiscript
if (!Char(']')) { if (!Char(']')) {
throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_position.line, m_position.col), *m_filename);
} }
if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { if ((prev_stack_top != m_match_stack.size()) && (!m_match_stack.back()->children.empty())) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {
build_match<eval::Inline_Range_AST_Node<Tracer>>(prev_stack_top); build_match<eval::Inline_Range_AST_Node<Tracer>>(prev_stack_top);
} }
@ -2218,18 +2263,25 @@ namespace chaiscript
/// Reads a unary prefixed expression from input /// Reads a unary prefixed expression from input
bool Prefix() { bool Prefix() {
const auto prev_stack_top = m_match_stack.size(); const auto prev_stack_top = m_match_stack.size();
constexpr const std::array<const char *, 6> prefix_opers{{"++", "--", "-", "+", "!", "~"}}; using SS = utility::Static_String;
constexpr const std::array<utility::Static_String, 6> prefix_opers{
SS{"++"},
SS{"--"},
SS{"-"},
SS{"+"},
SS{"!"},
SS{"~"}};
for (const auto &oper : prefix_opers) for (const auto &oper : prefix_opers)
{ {
bool is_char = strlen(oper) == 1; const bool is_char = oper.size() == 1;
if ((is_char && Char(oper[0])) || (!is_char && Symbol(oper))) if ((is_char && Char(oper.c_str()[0])) || (!is_char && Symbol(oper)))
{ {
if (!Operator(m_operators.size()-1)) { if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete prefix '" + std::string(oper) + "' expression", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete prefix '" + std::string(oper.c_str()) + "' expression", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Prefix_AST_Node<Tracer>>(prev_stack_top, oper); build_match<eval::Prefix_AST_Node<Tracer>>(prev_stack_top, oper.c_str());
return true; return true;
} }
} }
@ -2244,8 +2296,8 @@ namespace chaiscript
bool Operator_Helper(const size_t t_precedence, std::string &oper) { bool Operator_Helper(const size_t t_precedence, std::string &oper) {
for (auto & elem : m_operator_matches[t_precedence]) { for (auto & elem : m_operator_matches[t_precedence]) {
if (Symbol(elem.c_str())) { if (Symbol(elem)) {
oper = elem; oper = elem.c_str();
return true; return true;
} }
} }
@ -2274,7 +2326,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete '" + oper + "' expression", throw exception::eval_error("Incomplete '" + oper + "' expression",
File_Position(m_position.line, m_position.col), *m_filename); File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Ternary_Cond_AST_Node<Tracer>>(prev_stack_top); build_match<eval::If_AST_Node<Tracer>>(prev_stack_top);
} }
else { else {
throw exception::eval_error("Incomplete '" + oper + "' expression", throw exception::eval_error("Incomplete '" + oper + "' expression",
@ -2373,8 +2425,10 @@ namespace chaiscript
bool Equation() { bool Equation() {
const auto prev_stack_top = m_match_stack.size(); const auto prev_stack_top = m_match_stack.size();
using SS = utility::Static_String;
if (Operator()) { if (Operator()) {
for (const auto sym : {"=", ":=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "^=", "|="}) for (const auto sym : {SS{"="}, SS{":="}, SS{"+="}, SS{"-="}, SS{"*="}, SS{"/="}, SS{"%="}, SS{"<<="}, SS{">>="}, SS{"&="}, SS{"^="}, SS{"|="}})
{ {
if (Symbol(sym, true)) { if (Symbol(sym, true)) {
SkipWS(true); SkipWS(true);
@ -2382,7 +2436,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Equation_AST_Node<Tracer>>(prev_stack_top, sym); build_match<eval::Equation_AST_Node<Tracer>>(prev_stack_top, sym.c_str());
return true; return true;
} }
} }
@ -2421,7 +2475,7 @@ namespace chaiscript
} }
/// Top level parser, starts parsing of all known parses /// Top level parser, starts parsing of all known parses
bool Statements() { bool Statements(const bool t_class_allowed = false) {
bool retval = false; bool retval = false;
bool has_more = true; bool has_more = true;
@ -2429,7 +2483,7 @@ namespace chaiscript
while (has_more) { while (has_more) {
const auto start = m_position; const auto start = m_position;
if (Def() || Try() || If() || While() || Class() || For() || Switch()) { if (Def() || Try() || If() || While() || Class(t_class_allowed) || For() || Switch()) {
if (!saw_eol) { if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename);
} }
@ -2492,7 +2546,7 @@ namespace chaiscript
/// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html)
} }
if (Statements()) { if (Statements(true)) {
if (m_position.has_more()) { if (m_position.has_more()) {
throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname); throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname);
} else { } else {
@ -2508,7 +2562,6 @@ namespace chaiscript
} }
} }
#if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX) #if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX)
#undef CHAISCRIPT_PUSHED_MIN_MAX #undef CHAISCRIPT_PUSHED_MIN_MAX
#pragma pop_macro("min") #pragma pop_macro("min")

View File

@ -15,10 +15,10 @@ namespace chaiscript
{ {
struct DLModule struct DLModule
{ {
DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) : m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{ {
if (!m_data) if (m_data == nullptr)
{ {
throw chaiscript::exception::load_module_error(dlerror()); throw chaiscript::exception::load_module_error(dlerror());
} }

View File

@ -10,10 +10,11 @@
namespace chaiscript { namespace chaiscript {
namespace eval { namespace eval {
struct Noop_Tracer
struct Noop_Tracer_Detail
{ {
template<typename T> template<typename T>
static void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{ {
} }
}; };
@ -22,13 +23,13 @@ namespace chaiscript {
struct Tracer : T... struct Tracer : T...
{ {
Tracer() = default; Tracer() = default;
Tracer(T ... t) explicit Tracer(T ... t)
: T(std::move(t))... : T(std::move(t))...
{ {
} }
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (T::trace(ds, node), 0)... }; (void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
} }
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
@ -36,6 +37,8 @@ namespace chaiscript {
} }
}; };
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
} }
} }

View File

@ -80,7 +80,7 @@ namespace chaiscript
struct DLModule struct DLModule
{ {
DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) : m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{ {
if (!m_data) if (!m_data)

View File

@ -0,0 +1,22 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
namespace chaiscript
{
namespace utility
{
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
}
}
}
#endif

View File

@ -386,12 +386,12 @@ class JSON
return "null"; return "null";
case Class::Object: { case Class::Object: {
std::string pad = ""; std::string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ); for( long i = 0; i < depth; ++i, pad += tab ) { }
std::string s = "{\n"; std::string s = "{\n";
bool skip = true; bool skip = true;
for( auto &p : *internal.Map ) { for( auto &p : *internal.Map ) {
if( !skip ) s += ",\n"; if( !skip ) { s += ",\n"; }
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false; skip = false;
} }
@ -402,7 +402,7 @@ class JSON
std::string s = "["; std::string s = "[";
bool skip = true; bool skip = true;
for( auto &p : *internal.List ) { for( auto &p : *internal.List ) {
if( !skip ) s += ", "; if( !skip ) { s += ", "; }
s += p.dump( depth + 1, tab ); s += p.dump( depth + 1, tab );
skip = false; skip = false;
} }
@ -426,8 +426,8 @@ class JSON
private: private:
static std::string json_escape( const std::string &str ) { static std::string json_escape( const std::string &str ) {
std::string output; std::string output;
for( size_t i = 0; i < str.length(); ++i ) for(char i : str) {
switch( str[i] ) { switch( i ) {
case '\"': output += "\\\""; break; case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break; case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break; case '\b': output += "\\b"; break;
@ -435,8 +435,9 @@ class JSON
case '\n': output += "\\n"; break; case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break; case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break; case '\t': output += "\\t"; break;
default : output += str[i]; break; default : output += i; break;
} }
}
return output; return output;
} }
@ -462,7 +463,7 @@ struct JSONParser {
} }
static void consume_ws( const std::string &str, size_t &offset ) { static void consume_ws( const std::string &str, size_t &offset ) {
while( isspace( str[offset] ) && offset <= str.size() ) ++offset; while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; }
} }
static JSON parse_object( const std::string &str, size_t &offset ) { static JSON parse_object( const std::string &str, size_t &offset ) {
@ -544,9 +545,9 @@ struct JSONParser {
val += "\\u" ; val += "\\u" ;
for( size_t i = 1; i <= 4; ++i ) { for( size_t i = 1; i <= 4; ++i ) {
c = str[offset+i]; c = str[offset+i];
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
val += c; val += c;
else { } else {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
} }
} }
@ -554,9 +555,9 @@ struct JSONParser {
} break; } break;
default : val += '\\'; break; default : val += '\\'; break;
} }
} } else {
else
val += c; val += c;
}
} }
++offset; ++offset;
return JSON(val); return JSON(val);
@ -569,30 +570,35 @@ struct JSONParser {
long exp = 0; long exp = 0;
for (; offset < str.size() ;) { for (; offset < str.size() ;) {
c = str[offset++]; c = str[offset++];
if( (c == '-') || (c >= '0' && c <= '9') ) if( (c == '-') || (c >= '0' && c <= '9') ) {
val += c; val += c;
else if( c == '.' ) { } else if( c == '.' ) {
val += c; val += c;
isDouble = true; isDouble = true;
} } else {
else
break; break;
}
} }
if( offset < str.size() && (c == 'E' || c == 'e' )) { if( offset < str.size() && (c == 'E' || c == 'e' )) {
c = str[ offset++ ]; c = str[ offset++ ];
if( c == '-' ) { exp_str += '-';} if( c == '-' ) {
else if( c == '+' ) { } exp_str += '-';
else --offset; } else if( c == '+' ) {
// do nothing
} else {
--offset;
}
for (; offset < str.size() ;) { for (; offset < str.size() ;) {
c = str[ offset++ ]; c = str[ offset++ ];
if( c >= '0' && c <= '9' ) if( c >= '0' && c <= '9' ) {
exp_str += c; exp_str += c;
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { } else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
} }
else else {
break; break;
}
} }
exp = chaiscript::parse_num<long>( exp_str ); exp = chaiscript::parse_num<long>( exp_str );
} }
@ -643,8 +649,9 @@ struct JSONParser {
case 't' : case 't' :
case 'f' : return parse_bool( str, offset ); case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset ); case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
return parse_number( str, offset ); return parse_number( str, offset );
}
} }
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
} }

View File

@ -0,0 +1,37 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript
{
namespace utility
{
struct Static_String
{
template<size_t N>
constexpr Static_String(const char (&str)[N])
: m_size(N-1), data(&str[0])
{
}
constexpr size_t size() const {
return m_size;
}
constexpr const char *c_str() const {
return data;
}
const size_t m_size;
const char *data = nullptr;
};
}
}
#endif

View File

@ -89,6 +89,29 @@ namespace chaiscript
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
} }
} }
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
} }
} }

View File

@ -27,12 +27,17 @@ Current Version: 6.0.0
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface * Modular optimization system; this can be accessed via the ChaiScript_Basic interface
* Execution tracing capability; also accessed via ChaiScript_Basic interface * Execution tracing capability; also accessed via ChaiScript_Basic interface
* range-based for loops `for( id : container ) { }` * range-based for loops `for( id : container ) { }`
* If-init expressions (ala C++17)
* Support for passing r-value references to functions
* Support for containing unique_ptr
* Add helpers for exposing enum classes to ChaiScript
#### Improvements #### Improvements
* Compile time improvements * Compile time improvements
* Compile size improvements * Compile size improvements
* Significant runtime improvements (see "Modular optimization system") * Significant runtime improvements (see "Modular optimization system")
* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman)
#### Improvements Still Need To Be Made #### Improvements Still Need To Be Made
@ -41,6 +46,9 @@ Current Version: 6.0.0
### Changes since 5.8.5 ### Changes since 5.8.5
* Optimize away `return` statements in lambdas also * Optimize away `return` statements in lambdas also
* Allow conversions to bool in conditionals
* Don't allow `class` statements inside of scopes
* Properly error when a dynamic object non-function member is called
### Changes since 5.8.4 ### Changes since 5.8.4
* Fix order of operations for prefix operators * Fix order of operations for prefix operators

View File

@ -25,7 +25,7 @@
char *mystrdup (const char *s) { char *mystrdup (const char *s) {
size_t len = strlen(s); // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len+1)); char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) return nullptr; // No memory if (d == nullptr) { return nullptr; } // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len+1, s); // Copy the characters strcpy_s(d, len+1, s); // Copy the characters
#else #else
@ -44,7 +44,7 @@ char* readline(const char* p)
} }
void add_history(const char*){} void add_history(const char* /*unused*/){}
void using_history(){} void using_history(){}
#endif #endif
@ -116,7 +116,7 @@ std::vector<std::string> default_search_paths()
{ {
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset( &rInfo, 0, sizeof(rInfo) );
if ( !dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname ) { if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
return paths; return paths;
} }
@ -184,7 +184,7 @@ std::string get_next_command() {
std::string retval("quit"); std::string retval("quit");
if ( ! std::cin.eof() ) { if ( ! std::cin.eof() ) {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw ) { if ( input_raw != nullptr ) {
add_history(input_raw); add_history(input_raw);
std::string val(input_raw); std::string val(input_raw);
@ -240,7 +240,7 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
} }
catch (const chaiscript::exception::eval_error &ee) { catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if (ee.call_stack.size() > 0) { if ( !ee.call_stack.empty() ) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")"; std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
} }
std::cout << '\n'; std::cout << '\n';
@ -277,7 +277,7 @@ int main(int argc, char *argv[])
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.push_back(""); usepaths.push_back("");
if (usepath) if (usepath != nullptr)
{ {
usepaths.push_back(usepath); usepaths.push_back(usepath);
} }
@ -286,7 +286,7 @@ int main(int argc, char *argv[])
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back(""); modulepaths.push_back("");
if (modulepath) if (modulepath != nullptr)
{ {
modulepaths.push_back(modulepath); modulepaths.push_back(modulepath);
} }
@ -308,7 +308,7 @@ int main(int argc, char *argv[])
++i; ++i;
} }
std::string arg( i ? argv[i] : "--interactive" ); std::string arg( i != 0 ? argv[i] : "--interactive" );
enum { eInteractive enum { eInteractive
, eCommand , eCommand
@ -319,9 +319,9 @@ int main(int argc, char *argv[])
if ( (i+1) >= argc ) { if ( (i+1) >= argc ) {
std::cout << "insufficient input following " << arg << '\n'; std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { }
arg = argv[++i]; arg = argv[++i];
}
} else if ( arg == "-" || arg == "--stdin" ) { } else if ( arg == "-" || arg == "--stdin" ) {
arg = "" ; arg = "" ;
std::string line; std::string line;

View File

@ -0,0 +1,8 @@
try {
parse("{ class C { var data; def C() {} } }")
assert_false(true)
} catch (e) {
assert_true(true)
}

View File

@ -990,6 +990,34 @@ TEST_CASE("Make sure ChaiScript object still compiles / executes")
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
} }
struct Count_Tracer
{
int count = 0;
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const chaiscript::eval::AST_Node_Impl<T> *)
{
++count;
}
};
TEST_CASE("Test count tracer")
{
typedef chaiscript::parser::ChaiScript_Parser< chaiscript::eval::Tracer<Count_Tracer>, chaiscript::optimizer::Optimizer_Default > Parser_Type;
chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library(),
std::make_unique<Parser_Type>());
Parser_Type &parser = dynamic_cast<Parser_Type &>(chai.get_parser());
const auto count = parser.get_tracer().count;
chai.eval("");
CHECK(parser.get_tracer().count > count);
}
TEST_CASE("Test stdlib options") TEST_CASE("Test stdlib options")
{ {
const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) { const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) {
@ -1057,6 +1085,47 @@ TEST_CASE("Test stdlib options")
test_has_external_scripts(chai); test_has_external_scripts(chai);
test_no_load_modules(chai); test_no_load_modules(chai);
} }
}
void uservalueref(int &&)
{
}
void usemoveonlytype(std::unique_ptr<int> &&)
{
}
TEST_CASE("Pass r-value reference to func")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::fun(&uservalueref), "uservalueref");
chai.add(chaiscript::fun(&usemoveonlytype), "usemoveonlytype");
chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
chai.eval("usemoveonlytype(iptr)");
}
TEST_CASE("Use unique_ptr")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::fun([](int &i){ ++i; }), "inci");
chai.add(chaiscript::fun([](int i){ ++i; }), "copyi");
chai.add(chaiscript::fun([](int *i){ ++(*i); }), "derefi");
chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
CHECK(chai.eval<int>("iptr") == 1);
chai.eval("inci(iptr)");
CHECK(chai.eval<int>("iptr") == 2);
chai.eval("copyi(iptr)");
CHECK(chai.eval<int>("iptr") == 2);
chai.eval("derefi(iptr)");
CHECK(chai.eval<int>("iptr") == 3);
} }