Compare commits
51 Commits
develop
...
typed_rewo
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4f99687f1e | ||
![]() |
7d11b7c5f1 | ||
![]() |
06b2893bfb | ||
![]() |
7ab6bce7fa | ||
![]() |
f9294c8cbe | ||
![]() |
80cc18bf2f | ||
![]() |
c68488388e | ||
![]() |
7d5a97aa2f | ||
![]() |
83c6df11f0 | ||
![]() |
10b984556d | ||
![]() |
cf2fa09d6c | ||
![]() |
f3f84594ee | ||
![]() |
57aa874c6e | ||
![]() |
32bd936a18 | ||
![]() |
498339c202 | ||
![]() |
56b4f465a1 | ||
![]() |
1a42614441 | ||
![]() |
6fa83bca85 | ||
![]() |
7d9dbc3d86 | ||
![]() |
49dfdfd15a | ||
![]() |
720395e47a | ||
![]() |
5e0a882b18 | ||
![]() |
9603d3910a | ||
![]() |
6f0d02f158 | ||
![]() |
8d808f75c0 | ||
![]() |
2a1632f213 | ||
![]() |
b594043eef | ||
![]() |
fe8f8a89a7 | ||
![]() |
40694c798c | ||
![]() |
443828fa23 | ||
![]() |
866db4ee8b | ||
![]() |
5e97f459d8 | ||
![]() |
e02ac78195 | ||
![]() |
62cd8031ac | ||
![]() |
61dfcb00c0 | ||
![]() |
4bf619c80f | ||
![]() |
08a68f310a | ||
![]() |
641ac1a1ae | ||
![]() |
2400c64c82 | ||
![]() |
1e584048ce | ||
![]() |
82a69ca043 | ||
![]() |
dfb2394b0b | ||
![]() |
c07f413694 | ||
![]() |
172ab7b8e4 | ||
![]() |
fe8ddd1869 | ||
![]() |
5cb6f6a1a2 | ||
![]() |
95256417ac | ||
![]() |
2d2251c1da | ||
![]() |
0adacc0b5e | ||
![]() |
818fd0b823 | ||
![]() |
bd9af5eff4 |
@ -695,11 +695,10 @@
|
||||
/// Begins a function or method definition
|
||||
///
|
||||
/// ~~~~~~~~
|
||||
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// annotation: meta-annotation on function, currently used as documentation. Optional.
|
||||
/// identifier: name of function. Required.
|
||||
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
|
||||
/// guards: guarding statement that act as a prerequisite for the function. Optional.
|
||||
|
@ -89,6 +89,54 @@ namespace chaiscript {
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Build_Info {
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Iter, typename Distance>
|
||||
Iter advance_copy(Iter iter, Distance distance) {
|
||||
std::advance(iter, static_cast<typename std::iterator_traits<Iter>::difference_type>(distance));
|
||||
|
@ -14,11 +14,15 @@
|
||||
#include <vector>
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "language/chaiscript_common.hpp"
|
||||
|
||||
//#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/operators.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/boxed_value.hpp"
|
||||
//#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.hpp"
|
||||
#include "dispatchkit/register_function.hpp"
|
||||
#include "utility/json_wrap.hpp"
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
@ -38,15 +42,15 @@ namespace chaiscript
|
||||
|
||||
static ModulePtr library()
|
||||
{
|
||||
using namespace bootstrap;
|
||||
// using namespace bootstrap;
|
||||
|
||||
auto lib = std::make_shared<Module>();
|
||||
Bootstrap::bootstrap(*lib);
|
||||
bootstrap::Bootstrap::bootstrap(*lib);
|
||||
|
||||
standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
|
||||
standard_library::string_type<std::string>("string", *lib);
|
||||
standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
|
||||
standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
|
||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
|
||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
|
||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
|
@ -108,6 +108,9 @@ namespace chaiscript
|
||||
|
||||
#else
|
||||
|
||||
#pragma message ("Threading without thread_local support is not well supported.")
|
||||
|
||||
|
||||
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
||||
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||
///
|
||||
|
@ -27,45 +27,52 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
auto bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
auto bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
});
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
|
||||
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
|
||||
{
|
||||
return [fo, o, f](Param ...param) -> Ret {
|
||||
return (fo.*f)(o, std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename F, typename O>
|
||||
auto bind_first(const F &f, O&& o)
|
||||
{
|
||||
return bind_first(f, std::forward<O>(o), &F::operator());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,32 +7,8 @@
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "dispatchkit.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
#include "operators.hpp"
|
||||
#include "proxy_constructors.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "proxy_functions_detail.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "../utility/utility.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@ -138,15 +114,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/// to_string function for internal use. Uses ostream operator<<
|
||||
template<typename Input>
|
||||
std::string to_string(Input i)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
@ -288,8 +255,6 @@ namespace chaiscript
|
||||
m.add(fun(&Boxed_Number::product), "*");
|
||||
m.add(fun(&Boxed_Number::remainder), "%");
|
||||
m.add(fun(&Boxed_Number::shift_right), ">>");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Create a bound function object. The first param is the function to bind
|
||||
@ -329,26 +294,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static void throw_exception(const Boxed_Value &bv) {
|
||||
throw bv;
|
||||
}
|
||||
|
||||
static std::string what(const std::exception &e)
|
||||
{
|
||||
return e.what();
|
||||
}
|
||||
|
||||
/// Boolean specialization of internal to_string function
|
||||
static std::string bool_to_string(bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||
const dispatch::Proxy_Function_Base *b)
|
||||
@ -384,7 +329,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||
static auto return_boxed_value_vector(const Function &f)
|
||||
{
|
||||
return [f](const dispatch::Proxy_Function_Base *b) {
|
||||
return do_return_boxed_value_vector(f, b);
|
||||
@ -407,13 +352,13 @@ namespace chaiscript
|
||||
m.add(user_type<std::exception>(), "exception");
|
||||
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||
|
||||
|
||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
|
||||
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what");
|
||||
|
||||
m.add(user_type<std::out_of_range>(), "out_of_range");
|
||||
m.add(user_type<std::logic_error>(), "logic_error");
|
||||
@ -425,7 +370,6 @@ namespace chaiscript
|
||||
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m.add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
|
||||
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
@ -520,15 +464,15 @@ namespace chaiscript
|
||||
operators::equal<bool>(m);
|
||||
operators::not_equal<bool>(m);
|
||||
|
||||
m.add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m.add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||
m.add(fun([](const std::string &s) { return s; }), "to_string");
|
||||
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string");
|
||||
m.add(fun(&unknown_assign), "=");
|
||||
m.add(fun(&throw_exception), "throw");
|
||||
m.add(fun(&what), "what");
|
||||
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
|
||||
|
||||
m.add(fun(&to_string<char>), "to_string");
|
||||
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
|
||||
m.add(fun(&Boxed_Number::to_string), "to_string");
|
||||
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
@ -552,10 +496,21 @@ namespace chaiscript
|
||||
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
|
||||
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
|
||||
|
||||
|
||||
operators::logical_compliment<bool>(m);
|
||||
|
||||
opers_arithmetic_pod(m);
|
||||
|
||||
|
||||
m.add(fun(&Build_Info::version_major), "version_major");
|
||||
m.add(fun(&Build_Info::version_minor), "version_minor");
|
||||
m.add(fun(&Build_Info::version_patch), "version_patch");
|
||||
m.add(fun(&Build_Info::version), "version");
|
||||
m.add(fun(&Build_Info::compiler_version), "compiler_version");
|
||||
m.add(fun(&Build_Info::compiler_name), "compiler_name");
|
||||
m.add(fun(&Build_Info::compiler_id), "compiler_id");
|
||||
m.add(fun(&Build_Info::debug_build), "debug_build");
|
||||
|
||||
|
||||
m.add(fun(&print), "print_string");
|
||||
m.add(fun(&println), "println_string");
|
||||
@ -580,9 +535,11 @@ namespace chaiscript
|
||||
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
||||
|
||||
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
|
||||
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
@ -593,13 +550,13 @@ namespace chaiscript
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
}), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
@ -621,24 +578,16 @@ namespace chaiscript
|
||||
{fun(&AST_Node::start), "start"},
|
||||
{fun(&AST_Node::end), "end"},
|
||||
{fun(&AST_Node::to_string), "to_string"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_node.children.begin(), t_node.children.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
}), "children"}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<parser::ChaiScript_Parser>(m,
|
||||
"ChaiScript_Parser",
|
||||
{ constructor<parser::ChaiScript_Parser ()>() },
|
||||
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
|
||||
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -69,11 +69,11 @@ namespace chaiscript
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
{
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
}
|
||||
}
|
||||
@ -84,11 +84,11 @@ namespace chaiscript
|
||||
try {
|
||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (...) {
|
||||
try {
|
||||
// try going the other way
|
||||
return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
@ -29,21 +29,50 @@ namespace chaiscript
|
||||
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
||||
if (ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
||||
if (ob.get_type_info().bare_equal_type_info(ti)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic Cast_Helper_Inner, for casting to any type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner
|
||||
{
|
||||
typedef typename std::add_const<Result>::type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,15 +86,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
typedef const Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
return static_cast<const Result *>(ob.get_const_ptr());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -73,15 +96,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||
{
|
||||
return static_cast<Result *>(ob.get_ptr());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -100,17 +117,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
typedef const Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -120,16 +129,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &>
|
||||
{
|
||||
typedef Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -137,9 +139,7 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
typedef std::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob.get().cast<std::shared_ptr<Result> >();
|
||||
}
|
||||
@ -149,9 +149,7 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
typedef std::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
@ -177,10 +175,7 @@ namespace chaiscript
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
|
||||
{
|
||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
||||
|
||||
typedef Boxed_Value::Sentinel<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
|
||||
return ob.pointer_sentinel(res);
|
||||
@ -204,9 +199,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef Boxed_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
@ -216,9 +209,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||
}
|
||||
@ -272,11 +263,9 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Cast_Helper
|
||||
{
|
||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
|
||||
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -162,17 +162,17 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::equals:
|
||||
case Operators::Opers::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
case Operators::Opers::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
case Operators::Opers::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
case Operators::Opers::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
case Operators::Opers::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
case Operators::Opers::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -184,10 +184,10 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::pre_increment:
|
||||
case Operators::Opers::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
case Operators::Opers::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
default:
|
||||
@ -202,20 +202,20 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
case Operators::Opers::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
case Operators::Opers::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
case Operators::Opers::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
case Operators::Opers::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
case Operators::Opers::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
@ -230,23 +230,23 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
case Operators::Opers::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
case Operators::Opers::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
case Operators::Opers::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
case Operators::Opers::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
case Operators::Opers::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
case Operators::Opers::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
@ -260,7 +260,7 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::bitwise_complement:
|
||||
case Operators::Opers::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -272,18 +272,18 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
case Operators::Opers::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
case Operators::Opers::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
case Operators::Opers::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
case Operators::Opers::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
case Operators::Opers::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
case Operators::Opers::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -295,9 +295,9 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::unary_minus:
|
||||
case Operators::Opers::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
case Operators::Opers::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -309,14 +309,14 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
case Operators::Opers::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
case Operators::Opers::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
case Operators::Opers::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
case Operators::Opers::difference:
|
||||
return const_var(t - u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -328,16 +328,16 @@ namespace chaiscript
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
|
||||
{
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
|
||||
return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -349,12 +349,12 @@ namespace chaiscript
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
|
||||
{
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -366,11 +366,11 @@ namespace chaiscript
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
|
||||
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -381,9 +381,9 @@ namespace chaiscript
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@ -645,71 +645,6 @@ namespace chaiscript
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
bool operator==(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator!=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
Boxed_Number operator--()
|
||||
{
|
||||
return oper(Operators::pre_decrement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator++()
|
||||
{
|
||||
return oper(Operators::pre_increment, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+() const
|
||||
{
|
||||
return oper(Operators::unary_plus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-() const
|
||||
{
|
||||
return oper(Operators::unary_minus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static void validate_boxed_number(const Boxed_Value &v)
|
||||
{
|
||||
const Type_Info &inp_ = v.get_type_info();
|
||||
@ -724,266 +659,165 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEq
|
||||
Boxed_Number operator=(const Boxed_Value &v)
|
||||
{
|
||||
validate_boxed_number(v);
|
||||
bv = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEq
|
||||
Boxed_Number operator=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::assign, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator~() const
|
||||
{
|
||||
return oper(Operators::bitwise_complement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator/=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator+=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator-=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator/(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::product, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_decrement, t_lhs.bv);
|
||||
return oper(Operators::Opers::pre_decrement, t_lhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number pre_increment(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_increment, t_lhs.bv);
|
||||
return oper(Operators::Opers::pre_increment, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::sum, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_plus, t_lhs.bv);
|
||||
return oper(Operators::Opers::unary_plus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_minus, t_lhs.bv);
|
||||
return oper(Operators::Opers::unary_minus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::difference, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::bitwise_complement, t_lhs.bv, Boxed_Value(0));
|
||||
return oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::quotient, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_left, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::product, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::remainder, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_right, t_lhs.bv, t_rhs.bv);
|
||||
return oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
|
||||
@ -1009,9 +843,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper<Boxed_Number>
|
||||
{
|
||||
typedef Boxed_Number Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return Boxed_Number(ob);
|
||||
}
|
||||
|
@ -77,9 +77,9 @@ namespace chaiscript
|
||||
|
||||
struct Object_Data
|
||||
{
|
||||
static std::unique_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<void>::get(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
@ -89,15 +89,15 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
{
|
||||
return get(*obj, t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(obj),
|
||||
false,
|
||||
@ -107,10 +107,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
{
|
||||
auto ptr = obj.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
false,
|
||||
@ -120,23 +120,23 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(T *t, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::ref(*t), t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const T *t, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(const T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::cref(*t), t_return_value);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||
{
|
||||
auto p = &obj.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
true,
|
||||
@ -146,11 +146,11 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(T t, bool t_return_value)
|
||||
static std::shared_ptr<Data> get(T t, bool t_return_value)
|
||||
{
|
||||
auto p = std::make_shared<T>(std::move(t));
|
||||
auto ptr = p.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(p)),
|
||||
false,
|
||||
@ -159,9 +159,9 @@ namespace chaiscript
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Data> get()
|
||||
static std::shared_ptr<Data> get()
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
Type_Info(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
@ -226,48 +226,39 @@ namespace chaiscript
|
||||
return m_data->m_type_info.bare_equal(ti);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &ptr, Data &data)
|
||||
: m_ptr(ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
m_data.get().m_data_ptr = m_ptr.get().get();
|
||||
m_data.get().m_const_data_ptr = m_ptr.get().get();
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) {
|
||||
m_ptr = std::move(s.m_ptr);
|
||||
m_data = std::move(s.m_data);
|
||||
}
|
||||
|
||||
Sentinel(Sentinel &&s)
|
||||
: m_ptr(std::move(s.m_ptr)),
|
||||
m_data(std::move(s.m_data))
|
||||
{
|
||||
}
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Sentinel<T> pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
{
|
||||
return Sentinel<T>(ptr, *(m_data.get()));
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &ptr, Data &data)
|
||||
: m_ptr(ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
m_data.get().m_data_ptr = m_ptr.get().get();
|
||||
m_data.get().m_const_data_ptr = m_ptr.get().get();
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) = default;
|
||||
Sentinel(Sentinel &&s) = default;
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
return Sentinel(ptr, *(m_data.get()));
|
||||
}
|
||||
|
||||
bool is_null() const noexcept
|
||||
|
@ -310,11 +310,6 @@ namespace chaiscript
|
||||
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "Multiple method dispatch function wrapper.";
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@ -381,7 +376,6 @@ namespace chaiscript
|
||||
typedef std::vector<Scope> StackData;
|
||||
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.reserve(2);
|
||||
stacks.emplace_back(1);
|
||||
@ -392,7 +386,7 @@ namespace chaiscript
|
||||
std::vector<StackData> stacks;
|
||||
|
||||
std::vector<std::vector<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
int call_depth = 0;
|
||||
};
|
||||
|
||||
/// Main class for the dispatchkit. Handles management
|
||||
@ -412,11 +406,9 @@ namespace chaiscript
|
||||
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
|
||||
State &operator=(const State &) = default;
|
||||
State() = default;
|
||||
State(const State &) = default;
|
||||
std::set<std::string> m_reserved_words
|
||||
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
||||
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"};
|
||||
};
|
||||
|
||||
Dispatch_Engine()
|
||||
@ -424,16 +416,12 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
~Dispatch_Engine()
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
Type_Conversions_State state(m_conversions, m_conversions.conversion_saves());
|
||||
return chaiscript::boxed_cast<Type>(bv, &state);
|
||||
return(chaiscript::boxed_cast<Type>(bv, &state));
|
||||
}
|
||||
|
||||
/// Add a new conversion for upcasting to a base class
|
||||
@ -886,12 +874,6 @@ namespace chaiscript
|
||||
return rets;
|
||||
}
|
||||
|
||||
void add_reserved_word(const std::string &name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_state.m_reserved_words.insert(name);
|
||||
}
|
||||
|
||||
const Type_Conversions &conversions() const
|
||||
{
|
||||
@ -1058,27 +1040,31 @@ namespace chaiscript
|
||||
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
|
||||
{
|
||||
std::vector<Type_Info> params = f.second->get_param_types();
|
||||
std::string annotation = f.second->annotation();
|
||||
std::vector<std::pair<std::string, Type_Info>> typed_params;
|
||||
|
||||
if (annotation.size() > 0) {
|
||||
std::cout << annotation;
|
||||
auto func(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(f.second));
|
||||
if (func) {
|
||||
typed_params = func->get_dynamic_param_types().types();
|
||||
}
|
||||
|
||||
|
||||
dump_type(params.front());
|
||||
std::cout << " " << f.first << "(";
|
||||
|
||||
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
|
||||
itr != params.end();
|
||||
)
|
||||
for (size_t i = 1; i < params.size(); ++i)
|
||||
{
|
||||
dump_type(*itr);
|
||||
++itr;
|
||||
if (!typed_params.empty() && !typed_params[i-1].first.empty()) {
|
||||
std::cout << typed_params[i-1].first;
|
||||
} else {
|
||||
dump_type(params[i]);
|
||||
}
|
||||
|
||||
if (itr != params.end())
|
||||
{
|
||||
if (i != params.size() - 1) {
|
||||
std::cout << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::cout << ") \n";
|
||||
}
|
||||
|
||||
@ -1285,92 +1271,156 @@ namespace chaiscript
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
|
||||
|
||||
static std::vector<Type_Info> param_types(const Proxy_Function &t_f)
|
||||
{
|
||||
assert(t_f);
|
||||
return t_f->get_param_types();
|
||||
}
|
||||
|
||||
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
|
||||
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
|
||||
static std::vector<std::pair<std::string, Type_Info>> param_types(const std::shared_ptr<const dispatch::Dynamic_Function_Interface> &t_f)
|
||||
{
|
||||
assert(t_f);
|
||||
const auto types = t_f->get_dynamic_param_types().types();
|
||||
std::vector<std::pair<std::string, Type_Info>> ret(1);
|
||||
ret.insert(ret.end(), types.begin(), types.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dynamic_lhs && dynamic_rhs)
|
||||
static Type_Info type_info(const std::pair<std::string, Type_Info> &t_ti)
|
||||
{
|
||||
return t_ti.second;
|
||||
}
|
||||
|
||||
static Type_Info type_info(const Type_Info &t_ti)
|
||||
{
|
||||
return t_ti;
|
||||
}
|
||||
|
||||
static std::string dynamic_type_name(const std::pair<std::string, Type_Info> &t_ti)
|
||||
{
|
||||
return t_ti.first.empty()?t_ti.second.name():t_ti.first;
|
||||
}
|
||||
|
||||
static std::string dynamic_type_name(const Type_Info &ti)
|
||||
{
|
||||
return ti.name();
|
||||
}
|
||||
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs)
|
||||
{
|
||||
if (dynamic_lhs->get_guard())
|
||||
assert(t_lhs);
|
||||
assert(t_rhs);
|
||||
const auto lhsparamtypes = param_types(t_lhs);
|
||||
const auto rhsparamtypes = param_types(t_rhs);
|
||||
|
||||
const auto lhssize = lhsparamtypes.size();
|
||||
const auto rhssize = rhsparamtypes.size();
|
||||
|
||||
constexpr auto boxed_type = user_type<Boxed_Value>();
|
||||
constexpr auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
constexpr auto dynamic_type = user_type<dispatch::Dynamic_Object>();
|
||||
|
||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||
{
|
||||
return dynamic_rhs->get_guard() ? false : true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const Type_Info lt = type_info(lhsparamtypes[i]);
|
||||
const Type_Info rt = type_info(rhsparamtypes[i]);
|
||||
const std::string ln = dynamic_type_name(lhsparamtypes[i]);
|
||||
const std::string rn = dynamic_type_name(rhsparamtypes[i]);
|
||||
|
||||
if (dynamic_lhs && !dynamic_rhs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( (lt.bare_equal(dynamic_type) || lt.is_undef())
|
||||
&& (rt.bare_equal(dynamic_type) || rt.is_undef()))
|
||||
{
|
||||
|
||||
if (!dynamic_lhs && dynamic_rhs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!ln.empty() && rn.empty()) {
|
||||
return true;
|
||||
} else if (ln.empty() && !rn.empty()) {
|
||||
return false;
|
||||
} else if (!ln.empty() && !rn.empty()) {
|
||||
if (ln < rn) {
|
||||
return true;
|
||||
} else if (rn < ln) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &lhsparamtypes = lhs->get_param_types();
|
||||
const auto &rhsparamtypes = rhs->get_param_types();
|
||||
// the remaining cases are handled by the is_const rules below
|
||||
}
|
||||
}
|
||||
|
||||
const auto lhssize = lhsparamtypes.size();
|
||||
const auto rhssize = rhsparamtypes.size();
|
||||
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
|
||||
{
|
||||
continue; // The first two types are essentially the same, next iteration
|
||||
}
|
||||
|
||||
static const auto boxed_type = user_type<Boxed_Value>();
|
||||
static const auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
// const is after non-const for the same type
|
||||
if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||
{
|
||||
const Type_Info < = lhsparamtypes[i];
|
||||
const Type_Info &rt = rhsparamtypes[i];
|
||||
|
||||
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
|
||||
{
|
||||
continue; // The first two types are essentially the same, next iteration
|
||||
}
|
||||
|
||||
// const is after non-const for the same type
|
||||
if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lt.bare_equal(rt) && !lt.is_const())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// boxed_values are sorted last
|
||||
if (lt.bare_equal(boxed_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_type))
|
||||
{
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
if (lt.bare_equal(rt) && !lt.is_const())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
// boxed_values are sorted last
|
||||
if (lt.bare_equal(boxed_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise, we want to sort by typeid
|
||||
return lt < rt;
|
||||
}
|
||||
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return false;
|
||||
// if everything else checks out, sort on guard
|
||||
//
|
||||
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_lhs));
|
||||
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_rhs));
|
||||
|
||||
if (dynamic_lhs && dynamic_rhs) {
|
||||
if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) {
|
||||
return true;
|
||||
} else if (dynamic_rhs->get_guard()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise, we want to sort by typeid
|
||||
return lt < rt;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
|
||||
{
|
||||
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(lhs));
|
||||
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(rhs));
|
||||
|
||||
if (dynamic_lhs && dynamic_rhs)
|
||||
{
|
||||
return params_less_than(dynamic_lhs, dynamic_rhs);
|
||||
} else if (dynamic_lhs) {
|
||||
return params_less_than(dynamic_lhs, rhs);
|
||||
} else if (dynamic_rhs) {
|
||||
return params_less_than(lhs, dynamic_rhs);
|
||||
} else {
|
||||
return params_less_than(lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1536,3 +1586,4 @@ namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace chaiscript
|
||||
/// A Proxy_Function implementation designed for calling a function
|
||||
/// that is automatically guarded based on the first param based on the
|
||||
/// param's type name
|
||||
class Dynamic_Object_Function final : public Proxy_Function_Base
|
||||
class Dynamic_Object_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
@ -71,6 +71,17 @@ namespace chaiscript
|
||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||
|
||||
Param_Types get_dynamic_param_types() const override {
|
||||
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
|
||||
|
||||
if (dynamic) {
|
||||
return dynamic->get_dynamic_param_types();
|
||||
} else {
|
||||
return Param_Types(get_param_types());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||
@ -98,12 +109,6 @@ namespace chaiscript
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@ -179,7 +184,7 @@ namespace chaiscript
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Constructor final : public Proxy_Function_Base
|
||||
class Dynamic_Object_Constructor final : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Constructor(
|
||||
@ -188,6 +193,7 @@ namespace chaiscript
|
||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||
{
|
||||
assert( t_func );
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
@ -205,6 +211,18 @@ namespace chaiscript
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
|
||||
virtual Param_Types get_dynamic_param_types() const {
|
||||
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
|
||||
|
||||
if (dynamic) {
|
||||
return dynamic->get_dynamic_param_types();
|
||||
} else {
|
||||
return Param_Types(get_param_types());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
@ -219,11 +237,6 @@ namespace chaiscript
|
||||
return m_func->call_match(new_vals, t_conversions);
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
|
@ -81,9 +81,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> &>
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@ -98,9 +96,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@ -115,9 +111,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
|
@ -146,6 +146,14 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret>
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret &>
|
||||
@ -154,11 +162,6 @@ namespace chaiscript
|
||||
{
|
||||
return Boxed_Value(std::ref(r));
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -16,414 +16,202 @@ namespace chaiscript
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// \todo make this return a decltype once we drop gcc 4.6
|
||||
template<typename L, typename R>
|
||||
auto assign(L l, R r) -> L&
|
||||
{
|
||||
return (l = r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
|
||||
{
|
||||
return (l &= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_xor(L l, R r) -> decltype((l^=r))
|
||||
{
|
||||
return (l ^= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
|
||||
{
|
||||
return (l |= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_difference(L l, R r) -> decltype(( l -= r))
|
||||
{
|
||||
return (l -= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
|
||||
{
|
||||
return (l <<= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_product(L l, R r) -> decltype(( l *= r ))
|
||||
{
|
||||
return (l *= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
|
||||
{
|
||||
return (l /= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
|
||||
{
|
||||
return (l %= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
|
||||
{
|
||||
return (l >>= r);
|
||||
}
|
||||
|
||||
/// \todo make this return a decltype once we drop gcc 4.6
|
||||
template<typename L, typename R>
|
||||
auto assign_sum(L l, R r) -> L&
|
||||
{
|
||||
return (l += r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto prefix_decrement(L l) -> decltype(( --l ))
|
||||
{
|
||||
return (--l);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto prefix_increment(L l) -> decltype(( ++l ))
|
||||
{
|
||||
return (++l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto equal(L l, R r) -> decltype(( l == r ))
|
||||
{
|
||||
return (l == r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto greater_than(L l, R r) -> decltype(( l > r ))
|
||||
{
|
||||
return (l > r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
|
||||
{
|
||||
return (l >= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto less_than(L l, R r) -> decltype(( l < r ))
|
||||
{
|
||||
return (l < r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
|
||||
{
|
||||
return (l <= r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto logical_compliment(L l) -> decltype(( !l ))
|
||||
{
|
||||
return (!l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto not_equal(L l, R r) -> decltype(( l != r ))
|
||||
{
|
||||
return (l != r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto addition(L l, R r) -> decltype(( l + r ))
|
||||
{
|
||||
return (l + r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto unary_plus(L l) -> decltype(( +l ))
|
||||
{
|
||||
return (+l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto subtraction(L l, R r) -> decltype(( l - r ))
|
||||
{
|
||||
return (l - r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto unary_minus(L l) -> decltype(( -l ))
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
return (-l);
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
return (-l);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_and(L l, R r) -> decltype(( l & r ))
|
||||
{
|
||||
return (l & r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto bitwise_compliment(L l) -> decltype(( ~l ))
|
||||
{
|
||||
return (~l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
|
||||
{
|
||||
return (l ^ r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_or(L l, R r) -> decltype(( l | r ))
|
||||
{
|
||||
return (l | r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto division(L l, R r) -> decltype(( l / r ))
|
||||
{
|
||||
return (l / r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto left_shift(L l, R r) -> decltype(( l << r ))
|
||||
{
|
||||
return l << r;
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto multiplication(L l, R r) -> decltype(( l * r ))
|
||||
{
|
||||
return l * r;
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto remainder(L l, R r) -> decltype(( l % r ))
|
||||
{
|
||||
return (l % r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto right_shift(L l, R r) -> decltype(( l >> r ))
|
||||
{
|
||||
return (l >> r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void assign(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_difference(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_product(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_quotient(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_sum(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_decrement(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_increment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void logical_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
|
||||
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void not_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void addition(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_plus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
|
||||
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subtraction(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_minus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
|
||||
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
|
||||
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void division(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void multiplication(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,13 @@ namespace chaiscript
|
||||
m_doti(user_type<Dynamic_Object>())
|
||||
{}
|
||||
|
||||
Param_Types(const std::vector<Type_Info> &t_types)
|
||||
: m_types(build_param_types(t_types)),
|
||||
m_has_types(false),
|
||||
m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
}
|
||||
|
||||
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
|
||||
: m_types(std::move(t_types)),
|
||||
m_has_types(false),
|
||||
@ -61,6 +68,18 @@ namespace chaiscript
|
||||
update_has_types();
|
||||
}
|
||||
|
||||
static std::vector<std::pair<std::string, Type_Info>> build_param_types(const std::vector<Type_Info> &t_types)
|
||||
{
|
||||
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||
std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval),
|
||||
[](const Type_Info &ti){
|
||||
return std::make_pair(std::string(), ti);
|
||||
}
|
||||
);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
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));
|
||||
@ -204,8 +223,6 @@ namespace chaiscript
|
||||
return m_arity;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (ti.is_undef()
|
||||
@ -295,22 +312,28 @@ namespace chaiscript
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
class Dynamic_Function_Interface
|
||||
{
|
||||
public:
|
||||
virtual ~Dynamic_Function_Interface() {}
|
||||
virtual Param_Types get_dynamic_param_types() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation that is not type safe, the called function
|
||||
* is expecting a vector<Boxed_Value> that it works with how it chooses.
|
||||
*/
|
||||
class Dynamic_Proxy_Function : public Proxy_Function_Base
|
||||
class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function(
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||
m_param_types(std::move(t_param_types)),
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description))
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
||||
{
|
||||
}
|
||||
|
||||
@ -343,12 +366,10 @@ namespace chaiscript
|
||||
return m_parsenode;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const override
|
||||
{
|
||||
return m_description;
|
||||
virtual Param_Types get_dynamic_param_types() const {
|
||||
return m_param_types;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
@ -366,6 +387,8 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||
{
|
||||
@ -387,7 +410,6 @@ namespace chaiscript
|
||||
Param_Types m_param_types;
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
|
||||
@ -401,13 +423,11 @@ namespace chaiscript
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Dynamic_Proxy_Function(
|
||||
t_arity,
|
||||
std::move(t_parsenode),
|
||||
std::move(t_param_types),
|
||||
std::move(t_description),
|
||||
std::move(t_guard)
|
||||
),
|
||||
m_f(std::move(t_f))
|
||||
@ -506,10 +526,6 @@ namespace chaiscript
|
||||
return args;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const override
|
||||
{
|
||||
return "Bound: " + m_f->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
|
||||
@ -554,11 +570,6 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return static_cast<int>(vals.size()) == get_arity()
|
||||
@ -595,8 +606,7 @@ namespace chaiscript
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
|
||||
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
|
||||
return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -648,7 +658,7 @@ namespace chaiscript
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
|
||||
return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
@ -693,11 +703,6 @@ namespace chaiscript
|
||||
return vals[0].get_type_info().bare_equal(user_type<Class>());
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@ -728,13 +733,13 @@ namespace chaiscript
|
||||
template<typename Type>
|
||||
auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
|
||||
{
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
|
||||
{
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
|
||||
}
|
||||
|
||||
|
||||
@ -887,6 +892,15 @@ namespace chaiscript
|
||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||
ordered_funcs.reserve(funcs.size());
|
||||
|
||||
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||
static auto boxed_type = user_type<Boxed_Value>();
|
||||
static auto dynamic_type = user_type<Dynamic_Object>();
|
||||
#else
|
||||
auto boxed_type = user_type<Boxed_Value>();
|
||||
auto dynamic_type = user_type<Dynamic_Object>();
|
||||
#endif
|
||||
|
||||
|
||||
for (const auto &func : funcs)
|
||||
{
|
||||
const auto arity = func->get_arity();
|
||||
@ -898,7 +912,10 @@ namespace chaiscript
|
||||
size_t numdiffs = 0;
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
|
||||
const auto &p_type = plist[i].get_type_info();
|
||||
const auto &f_type = func->get_param_types()[i+1];
|
||||
|
||||
if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type))
|
||||
{
|
||||
++numdiffs;
|
||||
}
|
||||
|
@ -99,17 +99,23 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each parameter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
/// The function attempts to unbox each parameter to the expected type.
|
||||
/// if any unboxing fails the execution of the function fails and
|
||||
/// the bad_boxed_cast is passed up to the caller.
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||
}
|
||||
|
||||
template<typename Callable, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
|
||||
}
|
||||
@ -118,34 +124,4 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,8 +29,8 @@ namespace chaiscript
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
constexpr Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void,
|
||||
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
|
||||
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
|
||||
@ -121,9 +121,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
@ -138,9 +136,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@ -158,9 +154,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@ -173,9 +167,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::reference_wrapper<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@ -188,9 +180,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@ -212,7 +202,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Type_Info user_type(const T &/*t*/)
|
||||
constexpr Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
@ -227,7 +217,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Type_Info user_type()
|
||||
constexpr Type_Info user_type()
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace chaiscript
|
||||
{
|
||||
|
||||
struct Operators {
|
||||
enum Opers
|
||||
enum class Opers
|
||||
{
|
||||
boolean_flag,
|
||||
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
||||
@ -31,7 +31,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
static const char *to_string(Opers t_oper) {
|
||||
const char *opers[] = {
|
||||
static const char *opers[] = {
|
||||
"",
|
||||
"==", "<", ">", "<=", ">=", "!=",
|
||||
"",
|
||||
@ -46,80 +46,80 @@ namespace chaiscript
|
||||
"+", "/", "*", "-", "+", "-",
|
||||
""
|
||||
};
|
||||
return opers[t_oper];
|
||||
return opers[static_cast<int>(t_oper)];
|
||||
}
|
||||
|
||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||
{
|
||||
if (t_str == "==")
|
||||
{
|
||||
return equals;
|
||||
return Opers::equals;
|
||||
} else if (t_str == "<") {
|
||||
return less_than;
|
||||
return Opers::less_than;
|
||||
} else if (t_str == ">") {
|
||||
return greater_than;
|
||||
return Opers::greater_than;
|
||||
} else if (t_str == "<=") {
|
||||
return less_than_equal;
|
||||
return Opers::less_than_equal;
|
||||
} else if (t_str == ">=") {
|
||||
return greater_than_equal;
|
||||
return Opers::greater_than_equal;
|
||||
} else if (t_str == "!=") {
|
||||
return not_equal;
|
||||
return Opers::not_equal;
|
||||
} else if (t_str == "=") {
|
||||
return assign;
|
||||
return Opers::assign;
|
||||
} else if (t_str == "++") {
|
||||
return pre_increment;
|
||||
return Opers::pre_increment;
|
||||
} else if (t_str == "--") {
|
||||
return pre_decrement;
|
||||
return Opers::pre_decrement;
|
||||
} else if (t_str == "*=") {
|
||||
return assign_product;
|
||||
return Opers::assign_product;
|
||||
} else if (t_str == "+=") {
|
||||
return assign_sum;
|
||||
return Opers::assign_sum;
|
||||
} else if (t_str == "-=") {
|
||||
return assign_difference;
|
||||
return Opers::assign_difference;
|
||||
} else if (t_str == "&=") {
|
||||
return assign_bitwise_and;
|
||||
return Opers::assign_bitwise_and;
|
||||
} else if (t_str == "|=") {
|
||||
return assign_bitwise_or;
|
||||
return Opers::assign_bitwise_or;
|
||||
} else if (t_str == "<<=") {
|
||||
return assign_shift_left;
|
||||
return Opers::assign_shift_left;
|
||||
} else if (t_str == ">>=") {
|
||||
return assign_shift_right;
|
||||
return Opers::assign_shift_right;
|
||||
} else if (t_str == "%=") {
|
||||
return assign_remainder;
|
||||
return Opers::assign_remainder;
|
||||
} else if (t_str == "^=") {
|
||||
return assign_bitwise_xor;
|
||||
return Opers::assign_bitwise_xor;
|
||||
} else if (t_str == "<<") {
|
||||
return shift_left;
|
||||
return Opers::shift_left;
|
||||
} else if (t_str == ">>") {
|
||||
return shift_right;
|
||||
return Opers::shift_right;
|
||||
} else if (t_str == "%") {
|
||||
return remainder;
|
||||
return Opers::remainder;
|
||||
} else if (t_str == "&") {
|
||||
return bitwise_and;
|
||||
return Opers::bitwise_and;
|
||||
} else if (t_str == "|") {
|
||||
return bitwise_or;
|
||||
return Opers::bitwise_or;
|
||||
} else if (t_str == "^") {
|
||||
return bitwise_xor;
|
||||
return Opers::bitwise_xor;
|
||||
} else if (t_str == "~") {
|
||||
return bitwise_complement;
|
||||
return Opers::bitwise_complement;
|
||||
} else if (t_str == "+") {
|
||||
if (t_is_unary) {
|
||||
return unary_plus;
|
||||
return Opers::unary_plus;
|
||||
} else {
|
||||
return sum;
|
||||
return Opers::sum;
|
||||
}
|
||||
} else if (t_str == "-") {
|
||||
if (t_is_unary) {
|
||||
return unary_minus;
|
||||
return Opers::unary_minus;
|
||||
} else {
|
||||
return difference;
|
||||
return Opers::difference;
|
||||
}
|
||||
} else if (t_str == "/") {
|
||||
return quotient;
|
||||
return Opers::quotient;
|
||||
} else if (t_str == "*") {
|
||||
return product;
|
||||
return Opers::product;
|
||||
} else {
|
||||
return invalid;
|
||||
return Opers::invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,28 +32,26 @@ namespace chaiscript
|
||||
|
||||
|
||||
/// Types of AST nodes available to the parser and eval
|
||||
class AST_Node_Type {
|
||||
public:
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl
|
||||
};
|
||||
enum class AST_Node_Type { Id, Fun_Call, Arg_List, Equation, Var_Decl,
|
||||
Array_Call, Dot_Access,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
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
|
||||
};
|
||||
|
||||
enum class Operator_Precidence { Ternary_Cond, Logical_Or, Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, Equality, Comparison, Shift, Addition, Multiplication };
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Helper lookup to get the name of each node type
|
||||
const char *ast_node_type_to_string(int ast_node_type) {
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
|
||||
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Arg_List", "Equation", "Var_Decl",
|
||||
"Array_Call", "Dot_Access",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
|
||||
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg", "Constant"};
|
||||
|
||||
return ast_node_types[ast_node_type];
|
||||
return ast_node_types[static_cast<int>(ast_node_type)];
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +99,18 @@ namespace chaiscript
|
||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const load_module_error &) = default;
|
||||
virtual ~load_module_error() noexcept = default;
|
||||
};
|
||||
|
||||
|
||||
/// Errors generated during parsing or evaluation
|
||||
struct eval_error : std::runtime_error {
|
||||
@ -161,12 +171,12 @@ namespace chaiscript
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
virtual ~eval_error() noexcept {}
|
||||
virtual ~eval_error() noexcept = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
static int id(const T& t)
|
||||
static AST_Node_Type id(const T& t)
|
||||
{
|
||||
return t->identifier;
|
||||
}
|
||||
@ -434,11 +444,10 @@ namespace chaiscript
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
||||
public:
|
||||
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
|
||||
const AST_Node_Type identifier;
|
||||
const std::string text;
|
||||
Parse_Location location;
|
||||
std::vector<AST_NodePtr> children;
|
||||
AST_NodePtr annotation;
|
||||
|
||||
const std::string &filename() const {
|
||||
return *location.filename;
|
||||
@ -452,14 +461,14 @@ namespace chaiscript
|
||||
return location.end;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (auto & elem : this->children) {
|
||||
oss << elem->pretty_print();
|
||||
oss << elem->pretty_print() << ' ';
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
@ -499,15 +508,15 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
|
||||
{
|
||||
std::replace(children.begin(), children.end(), t_child, t_new_child);
|
||||
}
|
||||
virtual ~AST_Node() = default;
|
||||
AST_Node(AST_Node &&) = default;
|
||||
AST_Node &operator=(AST_Node &&) = default;
|
||||
AST_Node(const AST_Node &) = delete;
|
||||
AST_Node& operator=(const AST_Node &) = delete;
|
||||
|
||||
virtual ~AST_Node() {}
|
||||
|
||||
protected:
|
||||
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc,
|
||||
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc,
|
||||
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
|
||||
identifier(t_id), text(std::move(t_ast_node_text)),
|
||||
location(std::move(t_loc)),
|
||||
@ -520,10 +529,6 @@ namespace chaiscript
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy and assignment explicitly unimplemented
|
||||
AST_Node(const AST_Node &) = delete;
|
||||
AST_Node& operator=(const AST_Node &) = delete;
|
||||
};
|
||||
|
||||
|
||||
@ -554,77 +559,83 @@ namespace chaiscript
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
Scope_Push_Pop(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_scope(m_ds.get().stack_holder());
|
||||
m_ds->new_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_scope(m_ds.get().stack_holder());
|
||||
m_ds->pop_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new function call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
Function_Push_Pop(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_ds.get()->save_function_params(t_params);
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_ds.get()->save_function_params(std::move(t_params));
|
||||
m_ds->save_function_params(std::move(t_params));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
Stack_Push_Pop(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_stack(m_ds.get().stack_holder());
|
||||
m_ds->new_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_stack(m_ds.get().stack_holder());
|
||||
m_ds->pop_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -33,14 +33,15 @@
|
||||
|
||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "chaiscript_windows.hpp"
|
||||
#elif _POSIX_VERSION
|
||||
#include "chaiscript_posix.hpp"
|
||||
#else
|
||||
#include "chaiscript_unknown.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
@ -49,205 +50,9 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const load_module_error &) = default;
|
||||
virtual ~load_module_error() noexcept {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
|
||||
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string to_string(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
template<typename T>
|
||||
static std::wstring to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_wstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
static std::string to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_string(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string get_error_message(DWORD t_err)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
std::string retval = "Unknown Error";
|
||||
#endif
|
||||
StringType lpMsgBuf = nullptr;
|
||||
|
||||
if (FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<StringType>(&lpMsgBuf),
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
|
||||
#else
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
|
||||
}
|
||||
|
||||
@ -286,8 +91,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Evaluates the given file and looks in the 'use' paths
|
||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths)
|
||||
@ -325,27 +128,6 @@ namespace chaiscript
|
||||
|
||||
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
void build_eval_system(const ModulePtr &t_lib) {
|
||||
m_engine.add_reserved_word("def");
|
||||
m_engine.add_reserved_word("fun");
|
||||
m_engine.add_reserved_word("while");
|
||||
m_engine.add_reserved_word("for");
|
||||
m_engine.add_reserved_word("if");
|
||||
m_engine.add_reserved_word("else");
|
||||
m_engine.add_reserved_word("&&");
|
||||
m_engine.add_reserved_word("||");
|
||||
m_engine.add_reserved_word(",");
|
||||
m_engine.add_reserved_word("auto");
|
||||
m_engine.add_reserved_word("return");
|
||||
m_engine.add_reserved_word("break");
|
||||
m_engine.add_reserved_word("true");
|
||||
m_engine.add_reserved_word("false");
|
||||
m_engine.add_reserved_word("class");
|
||||
m_engine.add_reserved_word("attr");
|
||||
m_engine.add_reserved_word("var");
|
||||
m_engine.add_reserved_word("global");
|
||||
m_engine.add_reserved_word("GLOBAL");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
if (t_lib)
|
||||
{
|
||||
add(t_lib);
|
||||
@ -397,16 +179,9 @@ namespace chaiscript
|
||||
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
||||
|
||||
m_engine.add(fun(&parse), "parse");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
||||
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
||||
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
|
||||
m_engine.add(fun(&ChaiScript::version), "version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_version), "compiler_version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_name), "compiler_name");
|
||||
m_engine.add(fun(&ChaiScript::compiler_id), "compiler_id");
|
||||
m_engine.add(fun(&ChaiScript::debug_build), "debug_build");
|
||||
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
@ -517,7 +292,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
// attempt to load the stdlib
|
||||
load_module("chaiscript_stdlib-" + version());
|
||||
load_module("chaiscript_stdlib-" + Build_Info::version());
|
||||
|
||||
build_eval_system(ModulePtr());
|
||||
}
|
||||
@ -544,53 +319,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
@ -805,7 +533,7 @@ namespace chaiscript
|
||||
{
|
||||
std::vector<exception::load_module_error> errors;
|
||||
std::string version_stripped_name = t_module_name;
|
||||
size_t version_pos = version_stripped_name.find("-"+version());
|
||||
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
||||
if (version_pos != std::string::npos)
|
||||
{
|
||||
version_stripped_name.erase(version_pos);
|
||||
@ -837,16 +565,14 @@ namespace chaiscript
|
||||
|
||||
std::string errstring;
|
||||
|
||||
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
|
||||
itr != errors.end();
|
||||
++itr)
|
||||
for (const auto &err : errors)
|
||||
{
|
||||
if (!errstring.empty())
|
||||
{
|
||||
errstring += "; ";
|
||||
}
|
||||
|
||||
errstring += itr->what();
|
||||
errstring += err.what();
|
||||
}
|
||||
|
||||
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
|
||||
@ -886,14 +612,7 @@ namespace chaiscript
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
|
||||
{
|
||||
try {
|
||||
return do_eval(t_script);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return eval(t_script, t_handler);
|
||||
}
|
||||
|
||||
/// \brief Evaluates a string and returns a typesafe result.
|
||||
@ -912,21 +631,14 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
try {
|
||||
return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
return m_engine.boxed_cast<Type>(bv);
|
||||
return(m_engine.boxed_cast<Type>(bv));
|
||||
}
|
||||
|
||||
|
||||
@ -958,14 +670,7 @@ namespace chaiscript
|
||||
/// \return result of the script execution
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return do_eval(load_file(t_filename), t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return eval(load_file(t_filename), t_handler, t_filename);
|
||||
}
|
||||
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
|
||||
@ -978,14 +683,7 @@ namespace chaiscript
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -93,17 +93,12 @@ namespace chaiscript
|
||||
return do_oper(t_ss, m_oper, text, lhs, rhs);
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
|
||||
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
|
||||
{
|
||||
try {
|
||||
if (t_oper != Operators::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
|
||||
if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
|
||||
{
|
||||
// If it's an arithmetic operation we want to short circuit dispatch
|
||||
try{
|
||||
@ -129,95 +124,42 @@ namespace chaiscript
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Int_AST_Node final : AST_Node {
|
||||
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
|
||||
m_value(std::move(t_bv)) { assert(text != ""); }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
};
|
||||
struct Constant_AST_Node final : AST_Node {
|
||||
Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value)
|
||||
: AST_Node(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)),
|
||||
m_value(std::move(t_value))
|
||||
{
|
||||
}
|
||||
|
||||
struct Float_AST_Node final : AST_Node {
|
||||
Float_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Float, std::move(t_loc)),
|
||||
m_value(std::move(t_bv)) { }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
Boxed_Value m_value;
|
||||
};
|
||||
|
||||
struct Id_AST_Node final : AST_Node {
|
||||
Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)),
|
||||
m_value(get_value(t_ast_node_text)), m_loc(0)
|
||||
m_loc(0)
|
||||
{ }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
if (!m_value.is_undef())
|
||||
{
|
||||
return m_value;
|
||||
} else {
|
||||
try {
|
||||
return t_ss.get_object(this->text, m_loc);
|
||||
}
|
||||
catch (std::exception &) {
|
||||
throw exception::eval_error("Can not find object: " + this->text);
|
||||
}
|
||||
try {
|
||||
return t_ss.get_object(this->text, m_loc);
|
||||
}
|
||||
catch (std::exception &) {
|
||||
throw exception::eval_error("Can not find object: " + this->text);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Boxed_Value get_value(const std::string &t_text)
|
||||
{
|
||||
if (t_text == "true") {
|
||||
return const_var(true);
|
||||
} else if (t_text == "false") {
|
||||
return const_var(false);
|
||||
} else if (t_text == "Infinity") {
|
||||
return const_var(std::numeric_limits<double>::infinity());
|
||||
} else if (t_text == "NaN") {
|
||||
return const_var(std::numeric_limits<double>::quiet_NaN());
|
||||
} else if (t_text == "_") {
|
||||
return Boxed_Value(std::make_shared<dispatch::Placeholder_Object>());
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value m_value;
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Char_AST_Node final : AST_Node {
|
||||
Char_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Char, std::move(t_loc)) { }
|
||||
};
|
||||
|
||||
struct Str_AST_Node final : AST_Node {
|
||||
Str_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Str, std::move(t_loc)) { }
|
||||
};
|
||||
|
||||
struct Eol_AST_Node final : AST_Node {
|
||||
Eol_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Eol, std::move(t_loc)) { }
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Fun_Call_AST_Node final : AST_Node {
|
||||
@ -265,25 +207,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
int count = 0;
|
||||
for (const auto &child : this->children) {
|
||||
oss << child->pretty_print();
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
oss << "(";
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
oss << ")";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -293,40 +216,12 @@ namespace chaiscript
|
||||
Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
if (j != 0)
|
||||
{
|
||||
oss << " ";
|
||||
}
|
||||
|
||||
oss << this->children[j]->pretty_print();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Arg_List_AST_Node final : AST_Node {
|
||||
Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
if (j != 0)
|
||||
{
|
||||
oss << ", ";
|
||||
}
|
||||
|
||||
oss << this->children[j]->pretty_print();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string get_arg_name(const AST_NodePtr &t_node) {
|
||||
if (t_node->children.empty())
|
||||
@ -375,16 +270,16 @@ namespace chaiscript
|
||||
struct Equation_AST_Node final : AST_Node {
|
||||
Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)),
|
||||
m_oper(Operators::to_operator(children[1]->text))
|
||||
{ assert(children.size() == 3); }
|
||||
m_oper(Operators::to_operator(text))
|
||||
{ assert(children.size() == 2); }
|
||||
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
Boxed_Value rhs = this->children[2]->eval(t_ss);
|
||||
Boxed_Value rhs = this->children[1]->eval(t_ss);
|
||||
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
||||
|
||||
if (m_oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
|
||||
if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
|
||||
rhs.get_type_info().is_arithmetic())
|
||||
{
|
||||
try {
|
||||
@ -392,7 +287,7 @@ namespace chaiscript
|
||||
} catch (const std::exception &) {
|
||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
||||
}
|
||||
} else if (m_oper == Operators::assign) {
|
||||
} else if (m_oper == Operators::Opers::assign) {
|
||||
if (lhs.is_return_value()) {
|
||||
throw exception::eval_error("Error, cannot assign to temporary value.");
|
||||
}
|
||||
@ -400,9 +295,13 @@ namespace chaiscript
|
||||
try {
|
||||
|
||||
if (lhs.is_undef()) {
|
||||
if (!this->children.empty() &&
|
||||
!this->children[0]->children.empty()
|
||||
&& this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
|
||||
if ((!this->children.empty()
|
||||
&& ((this->children[0]->identifier == AST_Node_Type::Reference)
|
||||
|| (!this->children[0]->children.empty()
|
||||
&& this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
/// \todo This does not handle the case of an unassigned reference variable
|
||||
/// being assigned outside of its declaration
|
||||
@ -419,17 +318,17 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
try {
|
||||
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
else if (this->children[1]->text == ":=") {
|
||||
else if (this->text == ":=") {
|
||||
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
|
||||
lhs.assign(rhs);
|
||||
lhs.reset_return_value();
|
||||
@ -439,9 +338,9 @@ namespace chaiscript
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
} catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,31 +383,19 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
if (this->children[0]->identifier == AST_Node_Type::Reference)
|
||||
{
|
||||
return this->children[0]->eval(t_ss);
|
||||
} else {
|
||||
const std::string &idname = this->children[0]->text;
|
||||
const std::string &idname = this->children[0]->text;
|
||||
|
||||
try {
|
||||
Boxed_Value bv;
|
||||
t_ss.add_object(idname, bv);
|
||||
return bv;
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
throw exception::eval_error("Reserved word used as variable '" + idname + "'");
|
||||
} catch (const exception::name_conflict_error &e) {
|
||||
throw exception::eval_error("Variable redefined '" + e.name() + "'");
|
||||
}
|
||||
try {
|
||||
Boxed_Value bv;
|
||||
t_ss.add_object(idname, bv);
|
||||
return bv;
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
throw exception::eval_error("Reserved word used as variable '" + idname + "'");
|
||||
} catch (const exception::name_conflict_error &e) {
|
||||
throw exception::eval_error("Variable redefined '" + e.name() + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "var " + this->children[0]->text;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -530,20 +417,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << this->children[0]->pretty_print();
|
||||
|
||||
for (size_t i = 1; i < this->children.size(); ++i)
|
||||
{
|
||||
oss << "[";
|
||||
oss << this->children[i]->pretty_print();
|
||||
oss << "]";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
@ -553,8 +426,8 @@ namespace chaiscript
|
||||
Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)),
|
||||
m_fun_name(
|
||||
((children[2]->identifier == AST_Node_Type::Fun_Call) || (children[2]->identifier == AST_Node_Type::Array_Call))?
|
||||
children[2]->children[0]->text:children[2]->text) { }
|
||||
((children[1]->identifier == AST_Node_Type::Fun_Call) || (children[1]->identifier == AST_Node_Type::Array_Call))?
|
||||
children[1]->children[0]->text:children[1]->text) { }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
@ -564,9 +437,9 @@ namespace chaiscript
|
||||
std::vector<Boxed_Value> params{retval};
|
||||
|
||||
bool has_function_params = false;
|
||||
if (children[2]->children.size() > 1) {
|
||||
if (children[1]->children.size() > 1) {
|
||||
has_function_params = true;
|
||||
for (const auto &child : children[2]->children[1]->children) {
|
||||
for (const auto &child : children[1]->children[1]->children) {
|
||||
params.push_back(child->eval(t_ss));
|
||||
}
|
||||
}
|
||||
@ -588,9 +461,9 @@ namespace chaiscript
|
||||
retval = std::move(rv.retval);
|
||||
}
|
||||
|
||||
if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
|
||||
if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
|
||||
try {
|
||||
retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}, t_ss.conversions());
|
||||
retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
|
||||
@ -606,41 +479,6 @@ namespace chaiscript
|
||||
const std::string m_fun_name;
|
||||
};
|
||||
|
||||
struct Quoted_String_AST_Node final : AST_Node {
|
||||
Quoted_String_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Quoted_String, std::move(t_loc)),
|
||||
m_value(const_var(text)) { }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "\"" + text + "\"";
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
};
|
||||
|
||||
struct Single_Quoted_String_AST_Node final : AST_Node {
|
||||
Single_Quoted_String_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Single_Quoted_String, std::move(t_loc)),
|
||||
m_value(const_var(char(text.at(0)))) { }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "'" + text + "'";
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
};
|
||||
|
||||
struct Lambda_AST_Node final : AST_Node {
|
||||
Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
@ -736,7 +574,6 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
const std::string & l_function_name = this->children[0]->text;
|
||||
const std::string & l_annotation = this->annotation?this->annotation->text:"";
|
||||
const auto & func_node = this->children.back();
|
||||
t_ss->add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
@ -745,7 +582,7 @@ namespace chaiscript
|
||||
return detail::eval_function(engine, func_node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), this->children.back(),
|
||||
param_types, l_annotation, guard), l_function_name);
|
||||
param_types, guard), l_function_name);
|
||||
}
|
||||
catch (const exception::reserved_word_error &e) {
|
||||
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
|
||||
@ -816,32 +653,22 @@ namespace chaiscript
|
||||
|
||||
struct If_AST_Node final : AST_Node {
|
||||
If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { }
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children))
|
||||
{
|
||||
assert(children.size() == 2 || children.size() == 3);
|
||||
}
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
|
||||
if (get_bool_condition(children[0]->eval(t_ss))) {
|
||||
return children[1]->eval(t_ss);
|
||||
} else {
|
||||
if (children.size() > 2) {
|
||||
size_t i = 2;
|
||||
while (i < children.size()) {
|
||||
if (children[i]->text == "else") {
|
||||
return children[i+1]->eval(t_ss);
|
||||
}
|
||||
else if (children[i]->text == "else if") {
|
||||
if (get_bool_condition(children[i+1]->eval(t_ss))) {
|
||||
return children[i+2]->eval(t_ss);
|
||||
}
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
if (children.size() == 3) {
|
||||
return children[2]->eval(t_ss);
|
||||
} else {
|
||||
return void_var();
|
||||
}
|
||||
}
|
||||
|
||||
return void_var();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct For_AST_Node final : AST_Node {
|
||||
@ -973,11 +800,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "[" + AST_Node::pretty_print() + "]";
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
@ -1068,24 +890,24 @@ namespace chaiscript
|
||||
struct Prefix_AST_Node final : AST_Node {
|
||||
Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)),
|
||||
m_oper(Operators::to_operator(children[0]->text, true))
|
||||
m_oper(Operators::to_operator(text, true))
|
||||
{ }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||
Boxed_Value bv(children[1]->eval(t_ss));
|
||||
Boxed_Value bv(children[0]->eval(t_ss));
|
||||
|
||||
try {
|
||||
// short circuit arithmetic operations
|
||||
if (m_oper != Operators::invalid && m_oper != Operators::bitwise_and && bv.get_type_info().is_arithmetic())
|
||||
if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
|
||||
{
|
||||
return Boxed_Number::do_oper(m_oper, bv);
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
fpp.save_params({bv});
|
||||
return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}, t_ss.conversions());
|
||||
return t_ss->call_function(text, m_loc, {std::move(bv)}, t_ss.conversions());
|
||||
}
|
||||
} catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1153,11 +975,6 @@ namespace chaiscript
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Annotation_AST_Node final : AST_Node {
|
||||
Annotation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Annotation, std::move(t_loc)) { }
|
||||
};
|
||||
|
||||
struct Try_AST_Node final : AST_Node {
|
||||
Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
|
||||
@ -1324,7 +1141,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string & l_annotation = annotation?annotation->text:"";
|
||||
const std::string & function_name = children[static_cast<size_t>(1 + class_offset)]->text;
|
||||
auto node = children.back();
|
||||
|
||||
@ -1337,7 +1153,7 @@ namespace chaiscript
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard
|
||||
static_cast<int>(numparams), node, param_types, guard
|
||||
)
|
||||
),
|
||||
function_name);
|
||||
@ -1353,7 +1169,7 @@ namespace chaiscript
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
|
||||
static_cast<int>(numparams), node, param_types, guard), type),
|
||||
function_name);
|
||||
}
|
||||
}
|
||||
@ -1406,36 +1222,26 @@ namespace chaiscript
|
||||
struct Logical_And_AST_Node final : AST_Node {
|
||||
Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 3); }
|
||||
{ assert(children.size() == 2); }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
|
||||
{
|
||||
return const_var(get_bool_condition(children[0]->eval(t_ss))
|
||||
&& get_bool_condition(children[2]->eval(t_ss)));
|
||||
&& get_bool_condition(children[1]->eval(t_ss)));
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "(" + AST_Node::pretty_print() + ")";
|
||||
}
|
||||
};
|
||||
|
||||
struct Logical_Or_AST_Node final : AST_Node {
|
||||
Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 3); }
|
||||
{ assert(children.size() == 2); }
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
|
||||
{
|
||||
return const_var(get_bool_condition(children[0]->eval(t_ss))
|
||||
|| get_bool_condition(children[2]->eval(t_ss)));
|
||||
|| get_bool_condition(children[1]->eval(t_ss)));
|
||||
}
|
||||
|
||||
std::string pretty_print() const override
|
||||
{
|
||||
return "(" + AST_Node::pretty_print() + ")";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -147,19 +147,19 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static const std::array<AST_Node_Type::Type, 11> &create_operators() {
|
||||
static const std::array<AST_Node_Type::Type, 11> operators = { {
|
||||
AST_Node_Type::Ternary_Cond,
|
||||
AST_Node_Type::Logical_Or,
|
||||
AST_Node_Type::Logical_And,
|
||||
AST_Node_Type::Bitwise_Or,
|
||||
AST_Node_Type::Bitwise_Xor,
|
||||
AST_Node_Type::Bitwise_And,
|
||||
AST_Node_Type::Equality,
|
||||
AST_Node_Type::Comparison,
|
||||
AST_Node_Type::Shift,
|
||||
AST_Node_Type::Addition,
|
||||
AST_Node_Type::Multiplication
|
||||
static const std::array<Operator_Precidence, 11> &create_operators() {
|
||||
static const std::array<Operator_Precidence, 11> operators = { {
|
||||
Operator_Precidence::Ternary_Cond,
|
||||
Operator_Precidence::Logical_Or,
|
||||
Operator_Precidence::Logical_And,
|
||||
Operator_Precidence::Bitwise_Or,
|
||||
Operator_Precidence::Bitwise_Xor,
|
||||
Operator_Precidence::Bitwise_And,
|
||||
Operator_Precidence::Equality,
|
||||
Operator_Precidence::Comparison,
|
||||
Operator_Precidence::Shift,
|
||||
Operator_Precidence::Addition,
|
||||
Operator_Precidence::Multiplication
|
||||
} };
|
||||
return operators;
|
||||
}
|
||||
@ -167,10 +167,11 @@ namespace chaiscript
|
||||
static constexpr const char * const m_multiline_comment_begin = "/*";
|
||||
static constexpr const char * const m_multiline_comment_end = "*/";
|
||||
static constexpr const char * const m_singleline_comment = "//";
|
||||
static constexpr const char * const m_annotation = "#";
|
||||
|
||||
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::array<AST_Node_Type::Type, 11> &m_operators = create_operators();
|
||||
const std::array<Operator_Precidence, 11> &m_operators = create_operators();
|
||||
|
||||
std::shared_ptr<std::string> m_filename;
|
||||
std::vector<AST_NodePtr> m_match_stack;
|
||||
@ -178,8 +179,7 @@ namespace chaiscript
|
||||
|
||||
struct Position
|
||||
{
|
||||
Position()
|
||||
: line(-1), col(-1), m_last_col(-1) {}
|
||||
Position() = default;
|
||||
|
||||
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)
|
||||
@ -266,13 +266,13 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
int line;
|
||||
int col;
|
||||
int line = -1;
|
||||
int col = -1;
|
||||
|
||||
private:
|
||||
std::string::const_iterator m_pos;
|
||||
std::string::const_iterator m_end;
|
||||
int m_last_col;
|
||||
int m_last_col = -1;
|
||||
};
|
||||
|
||||
Position m_position;
|
||||
@ -298,59 +298,12 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Shows the current stack of matched ast_nodes
|
||||
void show_match_stack() const {
|
||||
for (auto & elem : m_match_stack) {
|
||||
//debug_print(match_stack[i]);
|
||||
std::cout << elem->to_string();
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the stack of matched ast_nodes
|
||||
void clear_match_stack() {
|
||||
m_match_stack.clear();
|
||||
}
|
||||
|
||||
/// Returns the front-most AST node
|
||||
AST_NodePtr ast() const {
|
||||
if (m_match_stack.empty()) throw exception::eval_error("Attempted to access AST of failed parse.");
|
||||
return m_match_stack.front();
|
||||
}
|
||||
|
||||
static std::map<std::string, int> count_fun_calls(const AST_NodePtr &p, bool in_loop) {
|
||||
if (p->identifier == AST_Node_Type::Fun_Call) {
|
||||
if (p->children[0]->identifier == AST_Node_Type::Id) {
|
||||
return std::map<std::string, int>{ {p->children[0]->text, in_loop?99:1} };
|
||||
}
|
||||
return std::map<std::string, int>();
|
||||
} else {
|
||||
std::map<std::string, int> counts;
|
||||
for (const auto &child : p->children) {
|
||||
auto childcounts = count_fun_calls(child, in_loop || p->identifier == AST_Node_Type::For || p->identifier == AST_Node_Type::While);
|
||||
for (const auto &count : childcounts) {
|
||||
counts[count.first] += count.second;
|
||||
}
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void optimize_blocks(AST_NodePtr &p)
|
||||
{
|
||||
for (auto &c : p->children)
|
||||
{
|
||||
if (c->identifier == AST_Node_Type::Block) {
|
||||
if (c->children.size() == 1) {
|
||||
// std::cout << "swapping out block child for block\n";
|
||||
c = c->children[0];
|
||||
}
|
||||
}
|
||||
optimize_blocks(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void optimize_returns(AST_NodePtr &p)
|
||||
{
|
||||
@ -372,19 +325,8 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static int count_nodes(const AST_NodePtr &p)
|
||||
{
|
||||
int count = 1;
|
||||
for (auto &c : p->children) {
|
||||
count += count_nodes(c);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true) {
|
||||
AST_NodePtr optimized_ast(bool t_optimize_returns = true) {
|
||||
AST_NodePtr p = ast();
|
||||
//Note, optimize_blocks is currently broken; it breaks stack management
|
||||
if (t_optimize_blocks) { optimize_blocks(p); }
|
||||
if (t_optimize_returns) { optimize_returns(p); }
|
||||
return p;
|
||||
}
|
||||
@ -458,6 +400,19 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (Symbol_(m_annotation)) {
|
||||
while (m_position.has_more()) {
|
||||
if (Symbol_("\r\n")) {
|
||||
m_position -= 2;
|
||||
break;
|
||||
} else if (Char_('\n')) {
|
||||
--m_position;
|
||||
break;
|
||||
} else {
|
||||
++m_position;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -742,20 +697,20 @@ namespace chaiscript
|
||||
if (Hex_()) {
|
||||
auto match = Position::str(start, m_position);
|
||||
auto bv = buildInt(16, match, true);
|
||||
m_match_stack.emplace_back(make_node<eval::Int_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
m_match_stack.emplace_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Binary_()) {
|
||||
auto match = Position::str(start, m_position);
|
||||
auto bv = buildInt(2, match, true);
|
||||
m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
return true;
|
||||
}
|
||||
if (Float_()) {
|
||||
auto match = Position::str(start, m_position);
|
||||
auto bv = buildFloat(match);
|
||||
m_match_stack.push_back(make_node<eval::Float_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -763,11 +718,11 @@ namespace chaiscript
|
||||
auto match = Position::str(start, m_position);
|
||||
if (!match.empty() && (match[0] == '0')) {
|
||||
auto bv = buildInt(8, match, false);
|
||||
m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
}
|
||||
else if (!match.empty()) {
|
||||
auto bv = buildInt(10, match, false);
|
||||
m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -825,16 +780,35 @@ namespace chaiscript
|
||||
|
||||
const auto start = m_position;
|
||||
if (Id_()) {
|
||||
m_match_stack.push_back(make_node<eval::Id_AST_Node>(
|
||||
[&]()->std::string{
|
||||
if (*start == '`') {
|
||||
//Id Literal
|
||||
return Position::str(start+1, m_position-1);
|
||||
} else {
|
||||
return Position::str(start, m_position);
|
||||
}
|
||||
}(),
|
||||
start.line, start.col));
|
||||
|
||||
const auto text = Position::str(start, m_position);
|
||||
if (text == "true") {
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, const_var(true)));
|
||||
} else if (text == "false") {
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, const_var(false)));
|
||||
} else if (text == "Infinity") {
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col,
|
||||
const_var(std::numeric_limits<double>::infinity())));
|
||||
} else if (text == "NaN") {
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col,
|
||||
const_var(std::numeric_limits<double>::quiet_NaN())));
|
||||
} else if (text == "_") {
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col,
|
||||
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
|
||||
} else {
|
||||
m_match_stack.push_back(make_node<eval::Id_AST_Node>(
|
||||
[&]()->std::string{
|
||||
if (*start == '`') {
|
||||
// 'escaped' literal, like an operator name
|
||||
return Position::str(start+1, m_position-1);
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}(),
|
||||
start.line, start.col));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -863,31 +837,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
/// Checks for a node annotation of the form "#<annotation>"
|
||||
bool Annotation() {
|
||||
SkipWS();
|
||||
const auto start = m_position;
|
||||
if (Symbol_("#")) {
|
||||
do {
|
||||
while (m_position.has_more()) {
|
||||
if (Eol_()) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
++m_position;
|
||||
}
|
||||
}
|
||||
} while (Symbol("#"));
|
||||
|
||||
auto match = Position::str(start, m_position);
|
||||
m_match_stack.push_back(make_node<eval::Annotation_AST_Node>(std::move(match), start.line, start.col));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a quoted string from input, without skipping initial whitespace
|
||||
bool Quoted_String_() {
|
||||
if (m_position.has_more() && (*m_position == '\"')) {
|
||||
@ -933,11 +882,11 @@ namespace chaiscript
|
||||
{
|
||||
string_type &match;
|
||||
typedef typename string_type::value_type char_type;
|
||||
bool is_escaped;
|
||||
bool is_interpolated;
|
||||
bool saw_interpolation_marker;
|
||||
bool is_octal;
|
||||
bool is_hex;
|
||||
bool is_escaped = false;
|
||||
bool is_interpolated = false;
|
||||
bool saw_interpolation_marker = false;
|
||||
bool is_octal = false;
|
||||
bool is_hex = false;
|
||||
const bool interpolation_allowed;
|
||||
|
||||
string_type octal_matches;
|
||||
@ -945,11 +894,6 @@ namespace chaiscript
|
||||
|
||||
Char_Parser(string_type &t_match, const bool t_interpolation_allowed)
|
||||
: match(t_match),
|
||||
is_escaped(false),
|
||||
is_interpolated(false),
|
||||
saw_interpolation_marker(false),
|
||||
is_octal(false),
|
||||
is_hex(false),
|
||||
interpolation_allowed(t_interpolation_allowed)
|
||||
{
|
||||
}
|
||||
@ -1086,13 +1030,11 @@ namespace chaiscript
|
||||
if (*s == '{') {
|
||||
//We've found an interpolation point
|
||||
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(match)));
|
||||
|
||||
if (cparser.is_interpolated) {
|
||||
//If we've seen previous interpolation, add on instead of making a new one
|
||||
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
|
||||
|
||||
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
|
||||
} else {
|
||||
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
|
||||
}
|
||||
|
||||
//We've finished with the part of the string up to this point, so clear it
|
||||
@ -1143,13 +1085,12 @@ namespace chaiscript
|
||||
return cparser.is_interpolated;
|
||||
}();
|
||||
|
||||
if (is_interpolated) {
|
||||
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(match)));
|
||||
|
||||
if (is_interpolated) {
|
||||
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
|
||||
} else {
|
||||
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -1209,7 +1150,7 @@ namespace chaiscript
|
||||
throw exception::eval_error("Single-quoted strings must be 1 character long", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
m_match_stack.push_back(make_node<eval::Single_Quoted_String_AST_Node>(match, start.line, start.col));
|
||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(char(match.at(0)))));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -1229,20 +1170,9 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Reads (and potentially captures) a char from input if it matches the parameter
|
||||
bool Char(const char t_c, bool t_capture = false) {
|
||||
bool Char(const char t_c) {
|
||||
SkipWS();
|
||||
|
||||
if (!t_capture) {
|
||||
return Char_(t_c);
|
||||
} else {
|
||||
const auto start = m_position;
|
||||
if (Char_(t_c)) {
|
||||
m_match_stack.push_back(make_node<eval::Char_AST_Node>(Position::str(start, m_position), start.line, start.col));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return Char_(t_c);
|
||||
}
|
||||
|
||||
/// Reads a string from input if it matches the parameter, without skipping initial whitespace
|
||||
@ -1265,7 +1195,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Reads (and potentially captures) a string from input if it matches the parameter
|
||||
bool Keyword(const char *t_s, bool t_capture = false) {
|
||||
bool Keyword(const char *t_s) {
|
||||
SkipWS();
|
||||
const auto start = m_position;
|
||||
bool retval = Keyword_(t_s);
|
||||
@ -1275,9 +1205,6 @@ namespace chaiscript
|
||||
retval = false;
|
||||
}
|
||||
|
||||
if ( t_capture && retval ) {
|
||||
m_match_stack.push_back(make_node<eval::Str_AST_Node>(Position::str(start, m_position), start.line, start.col));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1311,7 +1238,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Reads (and potentially captures) a symbol group from input if it matches the parameter
|
||||
bool Symbol(const char *t_s, const bool t_capture = false, const bool t_disallow_prevention=false) {
|
||||
bool Symbol(const char *t_s, const bool t_disallow_prevention=false) {
|
||||
SkipWS();
|
||||
const auto start = m_position;
|
||||
bool retval = Symbol_(t_s);
|
||||
@ -1326,10 +1253,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
if ( t_capture && retval ) {
|
||||
m_match_stack.push_back(make_node<eval::Str_AST_Node>(Position::str(start, m_position), start.line, start.col));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1372,14 +1295,13 @@ namespace chaiscript
|
||||
if (Arg(false)) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Arg(false)) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Char(','));
|
||||
}
|
||||
|
||||
while (Char(',')) {
|
||||
while (Eol()) {}
|
||||
if (!Arg(false)) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
build_match<eval::Arg_List_AST_Node>(prev_stack_top);
|
||||
|
||||
@ -1398,13 +1320,12 @@ namespace chaiscript
|
||||
if (Arg()) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Arg()) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Char(','));
|
||||
|
||||
while (Char(',')) {
|
||||
while (Eol()) {}
|
||||
if (!Arg()) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
build_match<eval::Arg_List_AST_Node>(prev_stack_top);
|
||||
@ -1425,13 +1346,11 @@ namespace chaiscript
|
||||
if (Equation()) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Equation()) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Char(','));
|
||||
while (Char(',')) {
|
||||
while (Eol()) {}
|
||||
if (!Equation()) {
|
||||
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1455,25 +1374,21 @@ namespace chaiscript
|
||||
} else if (Map_Pair()) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Map_Pair()) {
|
||||
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Char(','));
|
||||
while (Char(',')) {
|
||||
while (Eol()) {}
|
||||
if (!Map_Pair()) {
|
||||
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
build_match<eval::Arg_List_AST_Node>(prev_stack_top);
|
||||
} else if (Operator()) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Operator()) {
|
||||
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Char(','));
|
||||
while (Char(',')) {
|
||||
while (Eol()) {}
|
||||
if (!Operator()) {
|
||||
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
build_match<eval::Arg_List_AST_Node>(prev_stack_top);
|
||||
}
|
||||
@ -1527,13 +1442,6 @@ namespace chaiscript
|
||||
/// Reads a function definition from input
|
||||
bool Def(const bool t_class_context = false) {
|
||||
bool retval = false;
|
||||
AST_NodePtr annotation;
|
||||
|
||||
if (Annotation()) {
|
||||
while (Eol_()) {}
|
||||
annotation = m_match_stack.back();
|
||||
m_match_stack.pop_back();
|
||||
}
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
@ -1546,7 +1454,7 @@ namespace chaiscript
|
||||
|
||||
bool is_method = false;
|
||||
|
||||
if (Symbol("::", false)) {
|
||||
if (Symbol("::")) {
|
||||
//We're now a method
|
||||
is_method = true;
|
||||
|
||||
@ -1581,9 +1489,6 @@ namespace chaiscript
|
||||
build_match<eval::Def_AST_Node>(prev_stack_top);
|
||||
}
|
||||
|
||||
if (annotation) {
|
||||
m_match_stack.back()->annotation = std::move(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
@ -1608,7 +1513,7 @@ namespace chaiscript
|
||||
while (has_matches) {
|
||||
while (Eol()) {}
|
||||
has_matches = false;
|
||||
if (Keyword("catch", false)) {
|
||||
if (Keyword("catch")) {
|
||||
const auto catch_stack_top = m_match_stack.size();
|
||||
if (Char('(')) {
|
||||
if (!(Arg() && Char(')'))) {
|
||||
@ -1631,7 +1536,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
while (Eol()) {}
|
||||
if (Keyword("finally", false)) {
|
||||
if (Keyword("finally")) {
|
||||
const auto finally_stack_top = m_match_stack.size();
|
||||
|
||||
while (Eol()) {}
|
||||
@ -1675,25 +1580,8 @@ namespace chaiscript
|
||||
while (has_matches) {
|
||||
while (Eol()) {}
|
||||
has_matches = false;
|
||||
if (Keyword("else", true)) {
|
||||
if (Keyword("if")) {
|
||||
const AST_NodePtr back(m_match_stack.back());
|
||||
m_match_stack.back() =
|
||||
chaiscript::make_shared<AST_Node, eval::If_AST_Node>("else if", back->location, back->children);
|
||||
m_match_stack.back()->annotation = back->annotation;
|
||||
if (!Char('(')) {
|
||||
throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
if (!(Operator() && Char(')'))) {
|
||||
throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
while (Eol()) {}
|
||||
|
||||
if (!Block()) {
|
||||
throw exception::eval_error("Incomplete 'else if' block", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
if (Keyword("else")) {
|
||||
if (If()) {
|
||||
has_matches = true;
|
||||
} else {
|
||||
while (Eol()) {}
|
||||
@ -2032,7 +1920,7 @@ namespace chaiscript
|
||||
func_call->children.insert(func_call->children.begin(), dot_access->children.back());
|
||||
dot_access->children.pop_back();
|
||||
dot_access->children.push_back(std::move(func_call));
|
||||
if (dot_access->children.size() != 3) 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));
|
||||
}
|
||||
}
|
||||
@ -2045,13 +1933,13 @@ namespace chaiscript
|
||||
|
||||
build_match<eval::Array_Call_AST_Node>(prev_stack_top);
|
||||
}
|
||||
else if (Symbol(".", true)) {
|
||||
else if (Symbol(".")) {
|
||||
has_more = true;
|
||||
if (!(Id())) {
|
||||
throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 3) {
|
||||
if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 2) {
|
||||
throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
build_match<eval::Dot_Access_AST_Node>(prev_stack_top);
|
||||
@ -2079,11 +1967,14 @@ namespace chaiscript
|
||||
} else if (Keyword("auto") || Keyword("var") ) {
|
||||
retval = true;
|
||||
|
||||
if (!(Reference() || Id())) {
|
||||
if (Reference()) {
|
||||
// we built a reference node - continue
|
||||
} else if (Id()) {
|
||||
build_match<eval::Var_Decl_AST_Node>(prev_stack_top);
|
||||
} else {
|
||||
throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
build_match<eval::Var_Decl_AST_Node>(prev_stack_top);
|
||||
} else if (Keyword("GLOBAL") || Keyword("global")) {
|
||||
retval = true;
|
||||
|
||||
@ -2098,7 +1989,7 @@ namespace chaiscript
|
||||
if (!Id()) {
|
||||
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
if (!Symbol("::", false)) {
|
||||
if (!Symbol("::")) {
|
||||
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
if (!Id()) {
|
||||
@ -2162,7 +2053,7 @@ namespace chaiscript
|
||||
bool Reference() {
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Symbol("&", false)) {
|
||||
if (Symbol("&")) {
|
||||
if (!Id()) {
|
||||
throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
@ -2182,13 +2073,13 @@ namespace chaiscript
|
||||
for (const auto &oper : prefix_opers)
|
||||
{
|
||||
bool is_char = oper.size() == 1;
|
||||
if ((is_char && Char(oper[0], true)) || (!is_char && Symbol(oper.c_str(), true)))
|
||||
if ((is_char && Char(oper[0])) || (!is_char && Symbol(oper.c_str())))
|
||||
{
|
||||
if (!Operator(m_operators.size()-1)) {
|
||||
throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
build_match<eval::Prefix_AST_Node>(prev_stack_top);
|
||||
build_match<eval::Prefix_AST_Node>(prev_stack_top, oper);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2201,9 +2092,10 @@ namespace chaiscript
|
||||
return Var_Decl() || Dot_Fun_Array() || Prefix();
|
||||
}
|
||||
|
||||
bool Operator_Helper(const size_t t_precedence) {
|
||||
bool Operator_Helper(const size_t t_precedence, std::string &oper) {
|
||||
for (auto & elem : m_operator_matches[t_precedence]) {
|
||||
if (Symbol(elem.c_str(), true)) {
|
||||
if (Symbol(elem.c_str())) {
|
||||
oper = elem;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2217,61 +2109,80 @@ namespace chaiscript
|
||||
if (t_precedence < m_operators.size()) {
|
||||
if (Operator(t_precedence+1)) {
|
||||
retval = true;
|
||||
if (Operator_Helper(t_precedence)) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Operator(t_precedence+1)) {
|
||||
throw exception::eval_error("Incomplete "
|
||||
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
|
||||
File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
std::string oper;
|
||||
while (Operator_Helper(t_precedence, oper)) {
|
||||
while (Eol()) {}
|
||||
if (!Operator(t_precedence+1)) {
|
||||
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
||||
File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
AST_NodePtr oper = m_match_stack.at(m_match_stack.size()-2);
|
||||
|
||||
switch (m_operators[t_precedence]) {
|
||||
case(AST_Node_Type::Ternary_Cond) :
|
||||
m_match_stack.erase(advance_copy(m_match_stack.begin(), m_match_stack.size() - 2),
|
||||
advance_copy(m_match_stack.begin(), m_match_stack.size() - 1));
|
||||
if (Symbol(":")) {
|
||||
if (!Operator(t_precedence+1)) {
|
||||
throw exception::eval_error("Incomplete "
|
||||
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
|
||||
File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
build_match<eval::Ternary_Cond_AST_Node>(prev_stack_top);
|
||||
}
|
||||
else {
|
||||
throw exception::eval_error("Incomplete "
|
||||
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
|
||||
switch (m_operators[t_precedence]) {
|
||||
case(Operator_Precidence::Ternary_Cond) :
|
||||
if (Symbol(":")) {
|
||||
if (!Operator(t_precedence+1)) {
|
||||
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
||||
File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
break;
|
||||
build_match<eval::Ternary_Cond_AST_Node>(prev_stack_top);
|
||||
}
|
||||
else {
|
||||
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
||||
File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
break;
|
||||
|
||||
case(AST_Node_Type::Addition) :
|
||||
case(AST_Node_Type::Multiplication) :
|
||||
case(AST_Node_Type::Shift) :
|
||||
case(AST_Node_Type::Equality) :
|
||||
case(AST_Node_Type::Bitwise_And) :
|
||||
case(AST_Node_Type::Bitwise_Xor) :
|
||||
case(AST_Node_Type::Bitwise_Or) :
|
||||
case(AST_Node_Type::Comparison) :
|
||||
assert(m_match_stack.size() > 1);
|
||||
m_match_stack.erase(advance_copy(m_match_stack.begin(), m_match_stack.size() - 2),
|
||||
advance_copy(m_match_stack.begin(), m_match_stack.size() - 1));
|
||||
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, oper->text);
|
||||
break;
|
||||
case(Operator_Precidence::Addition) :
|
||||
case(Operator_Precidence::Multiplication) :
|
||||
case(Operator_Precidence::Shift) :
|
||||
case(Operator_Precidence::Equality) :
|
||||
case(Operator_Precidence::Bitwise_And) :
|
||||
case(Operator_Precidence::Bitwise_Xor) :
|
||||
case(Operator_Precidence::Bitwise_Or) :
|
||||
case(Operator_Precidence::Comparison) :
|
||||
{
|
||||
bool folded = false;
|
||||
const auto size = m_match_stack.size();
|
||||
|
||||
case(AST_Node_Type::Logical_And) :
|
||||
build_match<eval::Logical_And_AST_Node>(prev_stack_top);
|
||||
break;
|
||||
case(AST_Node_Type::Logical_Or) :
|
||||
build_match<eval::Logical_Or_AST_Node>(prev_stack_top);
|
||||
break;
|
||||
try {
|
||||
if (m_match_stack[size - 1]->identifier == AST_Node_Type::Constant
|
||||
&& m_match_stack[size - 2]->identifier == AST_Node_Type::Constant) {
|
||||
const auto parsed = Operators::to_operator(oper);
|
||||
if (parsed != Operators::Opers::invalid) {
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node>(m_match_stack[size-2])->m_value;
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node>(m_match_stack[size-1])->m_value;
|
||||
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
|
||||
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
|
||||
const auto start = m_match_stack[size-2]->location;
|
||||
const auto match = m_match_stack[size-2]->text + " " + oper + " " + m_match_stack[size-1]->text;
|
||||
m_match_stack.resize(size-2);
|
||||
m_match_stack.push_back(
|
||||
make_node<eval::Constant_AST_Node>(std::move(match), start.start.line, start.start.column, std::move(val)));
|
||||
folded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold
|
||||
}
|
||||
|
||||
default:
|
||||
throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
} while (Operator_Helper(t_precedence));
|
||||
if (!folded) {
|
||||
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, oper);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case(Operator_Precidence::Logical_And) :
|
||||
build_match<eval::Logical_And_AST_Node>(prev_stack_top, oper);
|
||||
break;
|
||||
case(Operator_Precidence::Logical_Or) :
|
||||
build_match<eval::Logical_Or_AST_Node>(prev_stack_top, oper);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2338,26 +2249,25 @@ namespace chaiscript
|
||||
|
||||
/// Parses a string of binary equation operators
|
||||
bool Equation() {
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Operator()) {
|
||||
retval = true;
|
||||
if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) ||
|
||||
Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) ||
|
||||
Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) ||
|
||||
Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) {
|
||||
SkipWS(true);
|
||||
if (!Equation()) {
|
||||
throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
for (const auto sym : {"=", ":=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "^=", "|="})
|
||||
{
|
||||
if (Symbol(sym, true)) {
|
||||
SkipWS(true);
|
||||
if (!Equation()) {
|
||||
throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
|
||||
build_match<eval::Equation_AST_Node>(prev_stack_top);
|
||||
build_match<eval::Equation_AST_Node>(prev_stack_top, sym);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Parses statements allowed inside of a class block
|
||||
|
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
// 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_POSIX_HPP_
|
||||
#define CHAISCRIPT_POSIX_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(DLModule &&) = default;
|
||||
DLModule &operator=(DLModule &&) = default;
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
27
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
27
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
// 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_UNKNOWN_HPP_
|
||||
#define CHAISCRIPT_UNKNOWN_HPP_
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
// 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_WINDOWS_HPP_
|
||||
#define CHAISCRIPT_WINDOWS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string to_string(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
template<typename T>
|
||||
static std::wstring to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_wstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
static std::string to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_string(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string get_error_message(DWORD t_err)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
std::string retval = "Unknown Error";
|
||||
#endif
|
||||
StringType lpMsgBuf = nullptr;
|
||||
|
||||
if (FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<StringType>(&lpMsgBuf),
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(DLModule &&) = default;
|
||||
DLModule &operator=(DLModule &&) = default;
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -12,9 +12,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/type_info.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
@ -10,7 +10,6 @@ def test_function(a)
|
||||
|
||||
// test_function tests
|
||||
assert_equal(test_function.get_arity(), 1);
|
||||
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
|
||||
assert_equal(test_function.get_contained_functions().size(), 0);
|
||||
assert_equal(test_function.get_param_types().size(), 2);
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
var parser := ChaiScript_Parser()
|
||||
var parse_success = parser.parse("3 + 4", "INPUT")
|
||||
var a := parser.ast()
|
||||
|
||||
assert_equal(eval(a), 7)
|
||||
|
||||
var childs := a.children.front().children
|
||||
var node := childs[0]
|
||||
|
||||
var parser2 := ChaiScript_Parser()
|
||||
parser2.parse("9", "INPUT")
|
||||
|
||||
|
||||
a.children.front().replace_child(childs[0], parser2.ast())
|
||||
|
||||
assert_equal(eval(a), 13)
|
||||
assert_equal(node.filename, "INPUT")
|
||||
|
||||
|
||||
|
||||
def my_fun()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
assert_equal(true, my_fun.has_parse_tree());
|
||||
assert_equal(false, `+`.has_parse_tree());
|
||||
|
||||
assert_throws("Function does not have a parse tree", fun() { `+`.get_parse_tree(); } );
|
||||
|
||||
var parsetree := my_fun.get_parse_tree();
|
||||
|
||||
assert_equal(1, eval(parsetree));
|
||||
|
||||
print(parsetree.text());
|
38
unittests/clone_object.chai
Normal file
38
unittests/clone_object.chai
Normal file
@ -0,0 +1,38 @@
|
||||
GLOBAL clone_count = 0;
|
||||
|
||||
class Cloneable
|
||||
{
|
||||
def Cloneable() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
def clone(Cloneable c)
|
||||
{
|
||||
print("Clone called");
|
||||
++clone_count;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
class MyObject
|
||||
{
|
||||
def MyObject() {
|
||||
this.data = Cloneable();
|
||||
}
|
||||
|
||||
var data;
|
||||
}
|
||||
|
||||
|
||||
assert_equal(0, clone_count);
|
||||
|
||||
var o = MyObject();
|
||||
|
||||
assert_equal(0, clone_count);
|
||||
|
||||
var p = o;
|
||||
|
||||
assert_equal(1, clone_count);
|
||||
|
@ -316,7 +316,8 @@ TEST_CASE("Function ordering")
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.eval("def test_fun(x) { return 3; }");
|
||||
chai.eval("def test_fun(x) : x == \"hi\" { return 4; }");
|
||||
// chai.eval("def test_fun(x) { return 5; }");
|
||||
chai.eval("def test_fun(double d) { return 5; }");
|
||||
|
||||
chai.add(chaiscript::fun(&function_ordering_test_one), "test_fun");
|
||||
chai.add(chaiscript::fun(&function_ordering_test_two), "test_fun");
|
||||
|
||||
@ -324,6 +325,7 @@ TEST_CASE("Function ordering")
|
||||
CHECK(chai.eval<int>("auto i = 1; test_fun(i)") == 2);
|
||||
CHECK(chai.eval<int>("test_fun(\"bob\")") == 3);
|
||||
CHECK(chai.eval<int>("test_fun(\"hi\")") == 4);
|
||||
CHECK(chai.eval<int>("test_fun(5.0)") == 5);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
@ -10,7 +10,6 @@ def test_function(a)
|
||||
|
||||
// test_function tests
|
||||
assert_equal(test_function.get_arity(), 1);
|
||||
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
|
||||
assert_equal(test_function.get_contained_functions().size(), 0);
|
||||
assert_equal(test_function.get_param_types().size(), 2);
|
||||
|
||||
|
@ -16,3 +16,8 @@ def f() {
|
||||
|
||||
f();
|
||||
|
||||
|
||||
global &h = v;
|
||||
assert_true(h == v)
|
||||
v = 3;
|
||||
assert_true(h == 3)
|
||||
|
@ -1,22 +1,9 @@
|
||||
auto& parser = ChaiScript_Parser()
|
||||
auto parse_success = parser.parse("3 + 4", "INPUT")
|
||||
auto& a = parser.ast()
|
||||
auto a = parse("3 + 4")
|
||||
|
||||
assert_equal(eval(a), 7)
|
||||
|
||||
auto& childs = a.children.front().children
|
||||
auto& node = childs[0]
|
||||
|
||||
auto& parser2 = ChaiScript_Parser()
|
||||
parser2.parse("9", "INPUT")
|
||||
|
||||
|
||||
a.children.front().replace_child(childs[0], parser2.ast())
|
||||
|
||||
assert_equal(eval(a), 13)
|
||||
assert_equal(node.filename, "INPUT")
|
||||
|
||||
|
||||
assert_equal(1, a.children.size());
|
||||
assert_equal("3 + 4", a.children[0].text());
|
||||
|
||||
def my_fun()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user