Compare commits

...

45 Commits

Author SHA1 Message Date
Jason Turner
3a951cea99 Extend the reserved object name registration to include some missing values such as break and return and such 2009-08-26 02:21:41 +00:00
Jonathan Turner
8620f4eaf9 Fix for issue 23, makes for and while loops live in their own deeper scope 2009-08-26 02:02:41 +00:00
Jonathan Turner
59ecf32f9b Add Eval_Error end extents and reserved word errors 2009-08-25 01:10:28 +00:00
Jason Turner
541e453098 check in of reserved word handling 2009-08-25 00:36:02 +00:00
Jason Turner
0b780593a6 Make for better error messages when a clone fails 2009-08-22 13:55:06 +00:00
Jason Turner
2e7c5f413e Cleanup get_function implementation 2009-08-21 22:51:12 +00:00
Jonathan Turner
7e5b7cbd7a Switch get_function to default to not doing object lookup. Correct method eval to maintain method lambda syntax. Add unit test for method lambda 2009-08-21 20:05:05 +00:00
Jonathan Turner
c539e0b458 Add unittest for 'use' feature 2009-08-21 18:26:34 +00:00
Jason Turner
1f011f3d5b Add "use" function for loading chai files from inside of ChaiScript and fix potential memory bug with filename const char * pointers being passed around 2009-08-21 03:33:57 +00:00
Jason Turner
a136236179 Fix dispatch for const boost::shared_ptr<> & parameters for functions, add a test to example.cpp and fix some issues with building example.cpp 2009-08-20 21:35:56 +00:00
Jonathan Turner
8840f06053 Allow floating point numbers without a zero before the decimal point 2009-08-20 14:50:13 +00:00
Jason Turner
00e4de774f Move "fun_helper" into detail namespace 2009-08-09 19:12:01 +00:00
Jason Turner
bc3a17b3b7 Port VC++ fix from last rev back to Linux 2009-08-09 18:42:32 +00:00
Jason Turner
4a57efde25 Correct bug with bootstrapping of Map type on windows. Also, make it easier to specify the type of a function being added at the time it is being added. 2009-08-09 16:49:14 +00:00
Jason Turner
cf94817869 Add missing new files from last checkin 2009-08-08 16:38:32 +00:00
Jason Turner
6775863415 Clean up chaiscript namespace by adding the "detail" namespace for internal functions/classes 2009-08-08 16:38:04 +00:00
Jason Turner
a3d4b6698a Favor filtering of functions during dispatch over exceptions to determine appropriate function to call. Results in approximately 50% reduction in runtime for long running scripts 2009-08-06 04:22:13 +00:00
Jason Turner
0ff107a818 Rename types_match to call_match in Proxy_Function to more closely match the semantics of the call 2009-08-06 01:35:12 +00:00
Jason Turner
ba6b392174 Approximate 20% reduction in runtime on long running scripts, based on profiling data. Reduce number of execution of object cache culling, reduction of copies of the stack and reduction of Boxed_Value copies 2009-08-05 02:43:13 +00:00
Jonathan Turner
5b424be4ed Add error to CMakeList.txt on missing Boost. Fix if sample 2009-07-26 13:33:58 +00:00
Jason Turner
669d6e9495 Cleanup comment in example.cpp 2009-07-25 13:48:44 +00:00
Jonathan Turner
9f614bba33 Update ticks in example to proper quotes 2009-07-24 13:31:15 +00:00
Jason Turner
0b789004e9 Make "clone" a chaiscript based operation instead of forcing the user to register a clone method. 2009-07-24 13:17:00 +00:00
Jason Turner
0d3c90a245 Add "type_name" function and port the "new" in prelude to use it instead of clone/clear. 2009-07-24 04:01:28 +00:00
Jonathan Turner
2f591a25a6 Add ltrim, rtrim, and trim 2009-07-23 17:35:39 +00:00
Jonathan Turner
4127a6ed41 Added 'clear'. Added 'push_back' to string. Added char. Added simple reverse 2009-07-23 17:01:07 +00:00
Jason Turner
4e412c0f6a Fix compilation error for G++ 2009-07-23 13:03:57 +00:00
Jason Turner
370121a9ff add example.cpp to build for VC++, fix minor bug in passing of & parameters to functor<>, move bootstrap functions into bootstrap namespace and clean up function names and add "retro" support for reversing of ranges. 2009-07-23 04:35:15 +00:00
Jason Turner
00ac8113c0 Add additional support for boost::shared_ptr as a return type 2009-07-21 02:00:39 +00:00
Jonathan Turner
72b6647718 Add missing return value 2009-07-20 19:53:31 +00:00
Jason Turner
daacbaa9e0 Correct for warnings and errors for the VC++ port. 2009-07-19 03:59:58 +00:00
Jason Turner
a5a1e3ee1b Revamped method for bootstrapping of types, using a new Module class that collects everything related to a type or group of types 2009-07-19 03:04:46 +00:00
Jason Turner
5a5b2929b0 Add additional functor example 2009-07-18 23:41:01 +00:00
Jason Turner
82bd46bb1a More usage cleansups 2009-07-18 23:34:08 +00:00
Jason Turner
4d4c26bf73 Major updates to the C++ API. Please see trunk/src/example.cpp to follow along 2009-07-18 18:05:54 +00:00
Jonathan Turner
ac817ff33a Change 'elseif' to 'else if' to better support C++ expectations 2009-07-17 14:16:27 +00:00
Jason Turner
689143aba5 Fix broken push_back in prelude, to correct for unit tests. 2009-07-16 23:53:13 +00:00
Jason Turner
9b733b2621 Correct g++ compilation error caused by r308, fix for casting to const boost::shared_ptr<> &. 2009-07-16 23:46:19 +00:00
Jason Turner
727dc7b0d6 Add support for boxed_cast<> to const boost::shared_ptr<Type> &, fixing the problem Jon was having 2009-07-16 21:30:01 +00:00
Jonathan Turner
3fc5f8e8e1 Guard push_back to ensure we have the push_back_ref before we call it 2009-07-16 20:32:33 +00:00
Jonathan Turner
aed493322b Clean up exception story so that there is only one exception type and one thing the user needs to catch 2009-07-16 13:24:15 +00:00
Jason Turner
8dbb43f45f Clean up last bug fix with full support for const & (and presumably some support for const *) contained types. 2009-07-15 23:36:10 +00:00
Jason Turner
ec2f81c674 Fix bug that jon discovered that affects attempting to return a reference to an object that shares a memory location with a containing object but has a different type. 2009-07-15 23:12:49 +00:00
Jonathan Turner
724ffdcb20 Oops, resetting CMakeList.txt to the correct one 2009-07-15 14:41:21 +00:00
Jonathan Turner
7c7e437b10 Clean up unnecessary Boxed_Value copies in eval 2009-07-15 14:40:53 +00:00
40 changed files with 2816 additions and 1928 deletions

View File

@@ -19,5 +19,7 @@ if (Boost_FOUND)
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp) #add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
target_link_libraries(chaiscript_eval ${Boost_LIBRARIES}) target_link_libraries(chaiscript_eval ${Boost_LIBRARIES})
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin) install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
else(Boost_FOUND)
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND) endif(Boost_FOUND)

View File

@@ -20,7 +20,7 @@
#include "dispatchkit/dispatchkit.hpp" #include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/function_call.hpp"
namespace chaiscript namespace chaiscript
{ {
/** /**
@@ -83,40 +83,29 @@ namespace chaiscript
}; };
/** /**
* Errors generated inside the parser * Errors generated during parsing or evaluation
*/
struct Parse_Error : public std::runtime_error {
std::string reason;
File_Position position;
const char *filename;
Parse_Error(const std::string &why, const File_Position &where, const char *fname) :
std::runtime_error("Parse error: \"" + why + "\" in '"
+ std::string(fname) + "' at: (" + boost::lexical_cast<std::string>(where.line+1) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), position(where), filename(fname)
{ }
Parse_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Parse error: \"" + why + "\" in '"
+ where->filename + "' line: " + boost::lexical_cast<std::string>(where->start.line+1)),
reason(why), position(where->start), filename(where->filename) {
}
virtual ~Parse_Error() throw() {}
};
/**
* Errors generated inside the evaluator
*/ */
struct Eval_Error : public std::runtime_error { struct Eval_Error : public std::runtime_error {
std::string reason; std::string reason;
TokenPtr location; File_Position start_position;
File_Position end_position;
const char *filename;
Eval_Error(const std::string &why, const TokenPtr where) Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
: std::runtime_error("Eval error: \"" + why + "\" in '" std::runtime_error("Error: \"" + why + "\" " +
+ where->filename + "' line: " + boost::lexical_cast<std::string>(where->start.line+1)), (std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
reason(why), location(where) { } + "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), start_position(where), end_position(where), filename(fname)
{ }
Eval_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Error: \"" + why + "\" " +
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
boost::lexical_cast<std::string>(where->start.column) + ")"),
reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
}
virtual ~Eval_Error() throw() {} virtual ~Eval_Error() throw() {}
}; };
@@ -125,10 +114,10 @@ namespace chaiscript
* Special type for returned values * Special type for returned values
*/ */
struct Return_Value { struct Return_Value {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
TokenPtr location; TokenPtr location;
Return_Value(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { } Return_Value(const Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { }
}; };
/** /**

View File

@@ -10,8 +10,12 @@
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace dispatchkit namespace chaiscript
{ {
namespace bootstrap
{
namespace detail
{
/** /**
* Set of helper functions for common operators * Set of helper functions for common operators
*/ */
@@ -207,78 +211,86 @@ namespace dispatchkit
return p1 -= P1(r.i); return p1 -= P1(r.i);
} }
} }
}
/** /**
* Add canonical form of "=" for type T * Add canonical form of "=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_equals(Dispatch_Engine &s) ModulePtr oper_equals(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &equals<const T&, const T&>, "="); m->add(fun(&detail::equals<const T&, const T&>), "=");
return m;
} }
/** /**
* Add canonical form of "+" for type T * Add canonical form of "+" for type T
*/ */
template<typename T> template<typename T>
void add_oper_add(Dispatch_Engine &s) ModulePtr oper_add(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &add<T, const T&, const T&>, "+"); m->add(fun(&detail::add<T, const T&, const T&>), "+");
return m;
} }
/** /**
* Add canonical form of "+=" for type T * Add canonical form of "+=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_add_equals(Dispatch_Engine &s) ModulePtr oper_add_equals(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &addsequal<T, T>, "+="); m->add(fun(&detail::addsequal<T, T>), "+=");
return m;
} }
/** /**
* Add canonical form of "-" for type T * Add canonical form of "-" for type T
*/ */
template<typename T> template<typename T>
void add_oper_subtract(Dispatch_Engine &s) ModulePtr oper_subtract(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &subtract<T, const T&, const T&>, "-"); m->add(fun(&detail::subtract<T, const T&, const T&>), "-");
return m;
} }
/** /**
* Add canonical form of "/" for type T * Add canonical form of "/" for type T
*/ */
template<typename T> template<typename T>
void add_oper_divide(Dispatch_Engine &s) ModulePtr oper_divide(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &divide<T, const T&, const T&>, "/"); m->add(fun(&detail::divide<T, const T&, const T&>), "/");
return m;
} }
/** /**
* Add canonical form of "*" for type T * Add canonical form of "*" for type T
*/ */
template<typename T> template<typename T>
void add_oper_multiply(Dispatch_Engine &s) ModulePtr oper_multiply(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &multiply<T, const T&, const T&>, "*"); m->add(fun(&detail::multiply<T, const T&, const T&>), "*");
return m;
} }
/** /**
* Add canonical form of "!=" for type T * Add canonical form of "!=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_not_equals(Dispatch_Engine &s) ModulePtr oper_not_equals(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &not_equals<const T&, const T&>, "!="); m->add(fun(&detail::not_equals<const T&, const T&>), "!=");
return m;
} }
/** /**
* Add user defined assignment operator for T = U * Add user defined assignment operator for T = U
*/ */
template<typename T, typename U> template<typename T, typename U>
void add_oper_assign_overload(Dispatch_Engine &s) ModulePtr oper_assign_overload(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &assign<T,U>, "="); m->add(fun(&detail::assign<T,U>), "=");
return m;
} }
@@ -286,9 +298,10 @@ namespace dispatchkit
* Add canonical form of "=" for type T * Add canonical form of "=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_assign(Dispatch_Engine &s) ModulePtr oper_assign(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &assign<T,T>, "="); m->add(fun(&detail::assign<T,T>), "=");
return m;
} }
@@ -296,9 +309,10 @@ namespace dispatchkit
* Add assignment operator for T = POD. * Add assignment operator for T = POD.
*/ */
template<typename T> template<typename T>
void add_oper_assign_pod(Dispatch_Engine &s) ModulePtr oper_assign_pod(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &assign_pod<T>, "="); m->add(fun(&detail::assign_pod<T>), "=");
return m;
} }
@@ -306,36 +320,40 @@ namespace dispatchkit
* Add canonical form of "<" for type T * Add canonical form of "<" for type T
*/ */
template<typename T> template<typename T>
void add_oper_less_than(Dispatch_Engine &s) ModulePtr oper_less_than(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &less_than<const T&, const T&>, "<"); m->add(fun(&detail::less_than<const T&, const T&>), "<");
return m;
} }
/** /**
* Add canonical form of ">" for type T * Add canonical form of ">" for type T
*/ */
template<typename T> template<typename T>
void add_oper_greater_than(Dispatch_Engine &s) ModulePtr oper_greater_than(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &greater_than<const T&, const T&>, ">"); m->add(fun(&detail::greater_than<const T&, const T&>), ">");
return m;
} }
/** /**
* Add canonical form of "<=" for type T * Add canonical form of "<=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_less_than_equals(Dispatch_Engine &s) ModulePtr oper_less_than_equals(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &less_than_equals<const T&, const T&>, "<="); m->add(fun(&detail::less_than_equals<const T&, const T&>), "<=");
return m;
} }
/** /**
* Add canonical form of ">=" for type T * Add canonical form of ">=" for type T
*/ */
template<typename T> template<typename T>
void add_oper_greater_than_equals(Dispatch_Engine &s) ModulePtr oper_greater_than_equals(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &greater_than_equals<const T&, const T&>, ">="); m->add(fun(&detail::greater_than_equals<const T&, const T&>), ">=");
return m;
} }
/** /**
@@ -343,23 +361,25 @@ namespace dispatchkit
* Examples: T < R, T == R, etc. * Examples: T < R, T == R, etc.
*/ */
template<typename T, typename R> template<typename T, typename R>
void add_opers_comparison_overload(Dispatch_Engine &s) ModulePtr opers_comparison_overload(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &equals<const T&, const R&>, "=="); m->add(fun(&detail::equals<const T&, const R&>), "==");
register_function(s, &not_equals<const T&, const R&>, "!="); m->add(fun(&detail::not_equals<const T&, const R&>), "!=");
register_function(s, &less_than<const T&, const R&>, "<"); m->add(fun(&detail::less_than<const T&, const R&>), "<");
register_function(s, &greater_than<const T&, const R&>, ">"); m->add(fun(&detail::greater_than<const T&, const R&>), ">");
register_function(s, &less_than_equals<const T&, const R&>, "<="); m->add(fun(&detail::less_than_equals<const T&, const R&>), "<=");
register_function(s, &greater_than_equals<const T&, const R&>, ">="); m->add(fun(&detail::greater_than_equals<const T&, const R&>), ">=");
return m;
} }
/** /**
* Add canonical forms of all comparison operators for type T * Add canonical forms of all comparison operators for type T
*/ */
template<typename T> template<typename T>
void add_opers_comparison(Dispatch_Engine &s) ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
{ {
add_opers_comparison_overload<T, T>(s); opers_comparison_overload<T, T>(m);
return m;
} }
/** /**
@@ -370,20 +390,21 @@ namespace dispatchkit
* T *= R; * T *= R;
*/ */
template<typename Ret, typename T, typename R> template<typename Ret, typename T, typename R>
void add_opers_arithmetic_overload(Dispatch_Engine &s) ModulePtr opers_arithmetic_overload(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &add<Ret, T, R>, "+"); m->add(fun(&detail::add<Ret, T, R>), "+");
register_function(s, &subtract<Ret, T, R>, "-"); m->add(fun(&detail::subtract<Ret, T, R>), "-");
register_function(s, &divide<Ret, T, R>, "/"); m->add(fun(&detail::divide<Ret, T, R>), "/");
register_function(s, &multiply<Ret, T, R>, "*"); m->add(fun(&detail::multiply<Ret, T, R>), "*");
register_function(s, &timesequal<T, R>, "*="); m->add(fun(&detail::timesequal<T, R>), "*=");
register_function(s, &dividesequal<T, R>, "/="); m->add(fun(&detail::dividesequal<T, R>), "/=");
register_function(s, &subtractsequal<T, R>, "-="); m->add(fun(&detail::subtractsequal<T, R>), "-=");
register_function(s, &addsequal<T, R>, "+="); m->add(fun(&detail::addsequal<T, R>), "+=");
register_function(s, &prefixincrement<T>, "++"); m->add(fun(&detail::prefixincrement<T>), "++");
register_function(s, &prefixdecrement<T>, "--"); m->add(fun(&detail::prefixdecrement<T>), "--");
register_function(s, &prefixnegate<T>, "-"); m->add(fun(&detail::prefixnegate<T>), "-");
register_function(s, &prefixnot<T>, "!"); m->add(fun(&detail::prefixnot<T>), "!");
return m;
} }
/** /**
@@ -391,43 +412,44 @@ namespace dispatchkit
* example: POD *= T, POD /= T * example: POD *= T, POD /= T
*/ */
template<typename T> template<typename T>
void add_opers_arithmetic_modify_pod(Dispatch_Engine &s) ModulePtr opers_arithmetic_modify_pod(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &timesequal_pod<T>, "*="); m->add(fun(&detail::timesequal_pod<T>), "*=");
register_function(s, &dividesequal_pod<T>, "/="); m->add(fun(&detail::dividesequal_pod<T>), "/=");
register_function(s, &subtractsequal_pod<T>, "-="); m->add(fun(&detail::subtractsequal_pod<T>), "-=");
register_function(s, &addsequal_pod<T>, "+="); m->add(fun(&detail::addsequal_pod<T>), "+=");
return m;
} }
/** /**
* Add a copy constructor for type T, also creates the standard * Add a copy constructor for type T
* function "clone" for the type. "clone" is a synonym for
* the copy constructor.
*/ */
template<typename T> template<typename T>
void add_copy_constructor(Dispatch_Engine &s, const std::string &type) ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
s.register_function(build_constructor<T, const T &>(), type); m->add(constructor<T (const T &)>(), type);
s.register_function(build_constructor<T, const T &>(), "clone"); return m;
} }
/** /**
* Add default and copy constructors (including "clone") for type T * Add default and copy constructors for type T
*/ */
template<typename T> template<typename T>
void add_basic_constructors(Dispatch_Engine &s, const std::string &type) ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
s.register_function(build_constructor<T>(), type); m->add(constructor<T ()>(), type);
add_copy_constructor<T>(s, type); copy_constructor<T>(type, m);
return m;
} }
/** /**
* Add POD type constructor for type T. ie: T = type(POD) * Add POD type constructor for type T. ie: T = type(POD)
*/ */
template<typename T> template<typename T>
void add_construct_pod(Dispatch_Engine &s, const std::string &type) ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &construct_pod<T>, type); m->add(fun(&detail::construct_pod<T>), type);
return m;
} }
/** /**
@@ -435,19 +457,20 @@ namespace dispatchkit
* T = type(const U &) * T = type(const U &)
*/ */
template<typename T, typename U> template<typename T, typename U>
void add_constructor_overload(Dispatch_Engine &s, const std::string &type) ModulePtr constructor_overload(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
s.register_function(build_constructor<T, const U &>(), type); m->add(constructor<T (const U &)>(), type);
return m;
} }
/** /**
* Add canonical forms of all arithmetic operators for type T * Add canonical forms of all arithmetic operators for type T
*/ */
template<typename T> template<typename T>
void add_opers_arithmetic(Dispatch_Engine &s) ModulePtr opers_arithmetic(ModulePtr m = ModulePtr(new Module()))
{ {
add_opers_arithmetic_overload<T, T, T>(s); opers_arithmetic_overload<T, T, T>(m);
return m;
} }
/** /**
@@ -487,24 +510,25 @@ namespace dispatchkit
* common conversions * common conversions
*/ */
template<typename T> template<typename T>
void bootstrap_pod_type(Dispatch_Engine &s, const std::string &name) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{ {
s.register_type<T>(name); m->add(user_type<T>(), name);
add_basic_constructors<T>(s, name); basic_constructors<T>(name, m);
add_oper_assign<T>(s); oper_assign<T>(m);
add_oper_assign_pod<T>(s); oper_assign_pod<T>(m);
add_construct_pod<T>(s, name); construct_pod<T>(name, m);
add_opers_arithmetic<T>(s); opers_arithmetic<T>(m);
add_opers_arithmetic_modify_pod<T>(s); opers_arithmetic_modify_pod<T>(m);
register_function(s, &to_string<T>, "to_string"); m->add(fun(&to_string<T>), "to_string");
register_function(s, &parse_string<T>, "to_" + name); m->add(fun(&parse_string<T>), "to_" + name);
return m;
} }
/** /**
* "clone" function for a shared_ptr type. This is used in the case * "clone" function for a shared_ptr type. This is used in the case
* where you do not want to make a deep copy of an object during cloning * where you do not want to make a deep copy of an object during cloning
* but want to instead maintain the shared_ptr. It is needed internally * but want to instead maintain the shared_ptr. It is needed internally
* for handling of boost::shared_ptr<Proxy_Function> object (that is, * for handling of Proxy_Function object (that is,
* function variables. * function variables.
*/ */
template<typename Type> template<typename Type>
@@ -530,8 +554,9 @@ namespace dispatchkit
* Class consisting of only static functions. All default bootstrapping occurs * Class consisting of only static functions. All default bootstrapping occurs
* from this class. * from this class.
*/ */
struct Bootstrap class Bootstrap
{ {
private:
/** /**
* Function allowing for assignment of an unknown type to any other value * Function allowing for assignment of an unknown type to any other value
*/ */
@@ -558,45 +583,25 @@ namespace dispatchkit
/** /**
* Add all comparison operators for POD types * Add all comparison operators for POD types
*/ */
static void add_opers_comparison_pod(Dispatch_Engine &s) static void opers_comparison_pod(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &equals<Boxed_POD_Value, Boxed_POD_Value>, "=="); m->add(fun(&detail::equals<Boxed_POD_Value, Boxed_POD_Value>), "==");
register_function(s, &not_equals<Boxed_POD_Value, Boxed_POD_Value>, "!="); m->add(fun(&detail::not_equals<Boxed_POD_Value, Boxed_POD_Value>), "!=");
register_function(s, &less_than<Boxed_POD_Value, Boxed_POD_Value>, "<"); m->add(fun(&detail::less_than<Boxed_POD_Value, Boxed_POD_Value>), "<");
register_function(s, &greater_than<Boxed_POD_Value, Boxed_POD_Value>, ">"); m->add(fun(&detail::greater_than<Boxed_POD_Value, Boxed_POD_Value>), ">");
register_function(s, &less_than_equals<Boxed_POD_Value, Boxed_POD_Value>, "<="); m->add(fun(&detail::less_than_equals<Boxed_POD_Value, Boxed_POD_Value>), "<=");
register_function(s, &greater_than_equals<Boxed_POD_Value, Boxed_POD_Value>, ">="); m->add(fun(&detail::greater_than_equals<Boxed_POD_Value, Boxed_POD_Value>), ">=");
} }
/** /**
* Add all arithmetic operators for PODs * Add all arithmetic operators for PODs
*/ */
static void add_opers_arithmetic_pod(Dispatch_Engine &s) static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{ {
register_function(s, &add<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>, "+"); m->add(fun(&detail::add<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "+");
register_function(s, &subtract<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>, "-"); m->add(fun(&detail::subtract<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "-");
register_function(s, &divide<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>, "/"); m->add(fun(&detail::divide<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "/");
register_function(s, &multiply<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>, "*"); m->add(fun(&detail::multiply<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "*");
}
/**
* Return true if the two Boxed_Value's share the same internal type
*/
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
}
/**
* return true if the Boxed_Value matches the registered type by name
*/
static bool is_type(const Dispatch_Engine &e, const std::string &type_name, Boxed_Value r)
{
try {
return e.get_type(type_name) == r.get_type_info();
} catch (const std::range_error &) {
return false;
}
} }
/** /**
@@ -611,9 +616,9 @@ namespace dispatchkit
throw arity_error(params.size(), 2); throw arity_error(params.size(), 2);
} }
boost::shared_ptr<Proxy_Function> f = boxed_cast<boost::shared_ptr<Proxy_Function> >(params[0]); Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
return Boxed_Value(boost::shared_ptr<Proxy_Function>(new Bound_Function(f, return Boxed_Value(Proxy_Function(new Bound_Function(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
@@ -628,60 +633,66 @@ namespace dispatchkit
throw arity_error(params.size(), 1); throw arity_error(params.size(), 1);
} }
boost::shared_ptr<Proxy_Function> f = boxed_cast<boost::shared_ptr<Proxy_Function> >(params[0]); Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
return Boxed_Value(f->types_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()))); return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
} }
static boost::shared_ptr<Dispatch_Engine> bootstrap2(boost::shared_ptr<Dispatch_Engine> e = boost::shared_ptr<Dispatch_Engine> (new Dispatch_Engine()))
{
e->add(user_type<void>(), "void");
return e;
}
public:
/** /**
* perform all common bootstrap functions for std::string, void and POD types * perform all common bootstrap functions for std::string, void and POD types
*/ */
static void bootstrap(Dispatch_Engine &s) static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module()))
{ {
s.register_type<void>("void"); m->add(user_type<void>(), "void");
s.register_type<bool>("bool"); m->add(user_type<bool>(), "bool");
s.register_type<Boxed_Value>("Object"); m->add(user_type<Boxed_Value>(), "Object");
s.register_type<Boxed_POD_Value>("PODObject"); m->add(user_type<Boxed_POD_Value>(), "PODObject");
s.register_type<Proxy_Function>("function"); m->add(user_type<Proxy_Function>(), "function");
add_basic_constructors<bool>(s, "bool"); basic_constructors<bool>("bool", m);
add_oper_assign<std::string>(s); oper_assign<std::string>(m);
add_oper_assign<bool>(s); oper_assign<bool>(m);
register_function(s, &to_string<const std::string &>, "internal_to_string"); m->add(fun(&to_string<const std::string &>), "internal_to_string");
register_function(s, &to_string<bool>, "internal_to_string"); m->add(fun(&to_string<bool>), "internal_to_string");
register_function(s, &unknown_assign, "="); m->add(fun(&unknown_assign), "=");
bootstrap_pod_type<double>(s, "double"); bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<int>(s, "int"); bootstrap_pod_type<int>("int", m);
bootstrap_pod_type<size_t>(s, "size_t"); bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>(s, "char"); bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<boost::int64_t>(s, "int64_t"); bootstrap_pod_type<boost::int64_t>("int64_t", m);
add_opers_comparison_pod(s); opers_comparison_pod(m);
add_opers_arithmetic_pod(s); opers_arithmetic_pod(m);
register_function(s, &modulus<int, int, int>, "%");
register_function(s, &print, "print_string"); m->add(fun(&detail::modulus<int, int, int>), "%");
register_function(s, &println, "println_string");
s.register_function(boost::function<void ()>(boost::bind(&dump_system, boost::ref(s))), "dump_system"); m->add(fun(&print), "print_string");
s.register_function(boost::function<void (Boxed_Value)>(boost::bind(&dump_object, _1, boost::ref(s))), "dump_object"); m->add(fun(&println), "println_string");
s.register_function(boost::function<bool (Boxed_Value, const std::string &)>(boost::bind(&is_type, boost::ref(s), _2, _1)),
"is_type");
s.register_function(boost::shared_ptr<Proxy_Function>(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))), m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
"bind"); "bind");
register_function(s, &shared_ptr_clone<Proxy_Function>, "clone"); m->add(fun(&shared_ptr_clone<Proxy_Function_Base>), "clone");
register_function(s, &ptr_assign<Proxy_Function>, "="); m->add(fun(&ptr_assign<Proxy_Function_Base>), "=");
s.register_function(boost::shared_ptr<Proxy_Function>(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))), m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
"call_exists"); "call_exists");
register_function(s, &type_match, "type_match"); m->add(fun(&type_match), "type_match");
return m;
} }
}; };
}
} }
#endif #endif

View File

@@ -5,39 +5,43 @@
// http://www.chaiscript.com // http://www.chaiscript.com
/** /**
* This file contains utility functions for registration of STL container * This file contains utility functions for registration of STL container
* classes. The methodology used is based on the SGI STL concepts. * classes. The methodology used is based on the SGI STL concepts.
* http://www.sgi.com/tech/stl/table_of_contents.html * http://www.sgi.com/tech/stl/table_of_contents.html
*/ */
#ifndef __bootstrap_stl_hpp #ifndef __bootstrap_stl_hpp__
#define __bootstrap_stl_hpp__ #define __bootstrap_stl_hpp__
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace dispatchkit namespace chaiscript
{ {
namespace bootstrap
{
/** /**
* Input_Range, based on the D concept of ranges. * Bidir_Range, based on the D concept of ranges.
* \todo Update the Range code to base its capabilities on * \todo Update the Range code to base its capabilities on
* the type_traits of the iterator passed in * the user_typetraits of the iterator passed in
*/ */
template<typename Container> template<typename Container>
struct Input_Range struct Bidir_Range
{ {
Input_Range(Container &c) typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end()) : m_begin(c.begin()), m_end(c.end())
{ {
} }
Input_Range(typename Container::iterator itr) Bidir_Range(typename Container::iterator itr)
: m_begin(itr), m_end(itr) : m_begin(itr), m_end(itr)
{ {
} }
Input_Range(const std::pair<typename Container::iterator, typename Container::iterator> &t_p) Bidir_Range(const std::pair<typename Container::iterator, typename Container::iterator> &t_p)
: m_begin(t_p.first), m_end(t_p.second) : m_begin(t_p.first), m_end(t_p.second)
{ {
} }
@@ -56,7 +60,16 @@ namespace dispatchkit
++m_begin; ++m_begin;
} }
typename std::iterator_traits<typename Container::iterator>::reference front() const void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
reference_type front() const
{ {
if (empty()) if (empty())
{ {
@@ -65,35 +78,78 @@ namespace dispatchkit
return *m_begin; return *m_begin;
} }
reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::iterator m_begin; typename Container::iterator m_begin;
typename Container::iterator m_end; typename Container::iterator m_end;
}; };
template<typename Range>
struct Retro
{
Retro(const Range &r)
: m_r(r)
{}
bool empty() { return m_r.empty(); }
void pop_front() { m_r.pop_back(); }
void pop_back() { m_r.pop_front(); }
typename Range::reference_type front() { return m_r.back(); }
typename Range::reference_type back() { return m_r.front(); }
private:
Range m_r;
};
/** /**
* Add Input_Range support for the given ContainerType * Add Bidir_Range support for the given ContainerType
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_input_range(Dispatch_Engine &system, const std::string &type) ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_type<Input_Range<ContainerType> >(type+"_Range"); m->add(user_type<Bidir_Range<ContainerType> >(), type + "_Range");
system.register_type<typename ContainerType::iterator>(type+"_Iterator"); m->add(user_type<Retro<Bidir_Range<ContainerType> > >(), type + "_Retro_Range");
m->add(user_type<typename ContainerType::iterator>(), type+"_Iterator");
system.register_function(build_constructor<Input_Range<ContainerType>, ContainerType &>(), "range"); copy_constructor<Bidir_Range<ContainerType> >(type + "_Range", m);
system.register_function(build_constructor<Input_Range<ContainerType>, copy_constructor<Retro<Bidir_Range<ContainerType> > >(type + "_Retro_Range", m);
typename ContainerType::iterator>(), "range");
m->add(constructor<Bidir_Range<ContainerType> (ContainerType &)>(), "range");
m->add(constructor<Bidir_Range<ContainerType> (typename ContainerType::iterator)>(), "range");
typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator> ItrPair; typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator> ItrPair;
system.register_function(build_constructor<Input_Range<ContainerType>, m->add(constructor<Bidir_Range<ContainerType> (const ItrPair &)>(), "range");
const ItrPair &>(), "range");
system.register_type<ItrPair>(type+"_Iterator_Pair"); m->add(user_type<ItrPair>(), type+"_Iterator_Pair");
m->add(fun(&Bidir_Range<ContainerType>::empty), "empty");
m->add(fun(&Bidir_Range<ContainerType>::pop_front), "pop_front");
m->add(fun(&Bidir_Range<ContainerType>::front), "front");
m->add(fun(&Bidir_Range<ContainerType>::pop_back), "pop_back");
m->add(fun(&Bidir_Range<ContainerType>::back), "back");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::empty), "empty");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::pop_front), "pop_front");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::front), "front");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::pop_back), "pop_back");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::back), "back");
m->add(constructor<Retro<Bidir_Range<ContainerType> > (const Bidir_Range<ContainerType> &)>(), "retro");
register_function(system, &Input_Range<ContainerType>::empty, "empty");
register_function(system, &Input_Range<ContainerType>::pop_front, "pop_front"); return m;
register_function(system, &Input_Range<ContainerType>::front, "front");
system.register_function(build_constructor<Input_Range<ContainerType>, const Input_Range<ContainerType> &>(), "clone");
} }
/** /**
@@ -101,8 +157,9 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/ReversibleContainer.html * http://www.sgi.com/tech/stl/ReversibleContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_reversible_container(Dispatch_Engine &/*system*/, const std::string &/*type*/) ModulePtr reversible_container_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
{ {
return m;
} }
/** /**
@@ -110,18 +167,19 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/RandomAccessContainer.html * http://www.sgi.com/tech/stl/RandomAccessContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_random_access_container(Dispatch_Engine &system, const std::string &type) ModulePtr random_access_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_reversible_container<ContainerType>(system, type); reversible_container_type<ContainerType>(type, m);
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t); typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
//In the interest of runtime safety for the system, we prefer the at() method for [] access, //In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition. //to throw an exception in an out of bounds condition.
system.register_function( m->add(
boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::at)), "[]"); fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::at))), "[]");
system.register_function( m->add(
boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::operator[])), "at"); fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::operator[]))), "at");
return m;
} }
/** /**
@@ -129,10 +187,11 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Assignable.html * http://www.sgi.com/tech/stl/Assignable.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_assignable(Dispatch_Engine &system, const std::string &type) ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
add_basic_constructors<ContainerType>(system, type); basic_constructors<ContainerType>(type, m);
add_oper_assign<ContainerType>(system); oper_assign<ContainerType>(m);
return m;
} }
/** /**
@@ -140,13 +199,16 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Container.html * http://www.sgi.com/tech/stl/Container.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_container(Dispatch_Engine &system, const std::string &type) ModulePtr container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_assignable<ContainerType>(system, type); assignable_type<ContainerType>(type, m);
register_function(system, &ContainerType::size, "size"); m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::size), "size");
register_function(system, &ContainerType::max_size, "max_size"); m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::max_size), "max_size");
register_function(system, &ContainerType::empty, "empty"); m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
return m;
} }
/** /**
@@ -154,10 +216,12 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/ForwardContainer.html * http://www.sgi.com/tech/stl/ForwardContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_forward_container(Dispatch_Engine &system, const std::string &type) ModulePtr forward_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_input_range<ContainerType>(system, type); input_range_type<ContainerType>(type, m);
bootstrap_container<ContainerType>(system, type); container_type<ContainerType>(type, m);
return m;
} }
/** /**
@@ -165,9 +229,10 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/DefaultConstructible.html * http://www.sgi.com/tech/stl/DefaultConstructible.html
*/ */
template<typename Type> template<typename Type>
void bootstrap_default_constructible(Dispatch_Engine &system, const std::string &type) ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_function(build_constructor<Type>(), type); m->add(constructor<Type ()>(), type);
return m;
} }
/** /**
@@ -211,10 +276,10 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Sequence.html * http://www.sgi.com/tech/stl/Sequence.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_sequence(Dispatch_Engine &system, const std::string &type) ModulePtr sequence_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_forward_container<ContainerType>(system, type); forward_container_type<ContainerType>(type, m);
bootstrap_default_constructible<ContainerType>(system, type); default_constructible_type<ContainerType>(type, m);
std::string insert_name; std::string insert_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
@@ -224,8 +289,10 @@ namespace dispatchkit
insert_name = "insert_at"; insert_name = "insert_at";
} }
register_function(system, &insert_at<ContainerType>, insert_name); m->add(fun(&insert_at<ContainerType>), insert_name);
register_function(system, &erase_at<ContainerType>, "erase_at"); m->add(fun(&erase_at<ContainerType>), "erase_at");
return m;
} }
/** /**
@@ -233,14 +300,14 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/BackInsertionSequence.html * http://www.sgi.com/tech/stl/BackInsertionSequence.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_back_insertion_sequence(Dispatch_Engine &system, const std::string &type) ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_sequence<ContainerType>(system, type); sequence_type<ContainerType>(type, m);
typedef typename ContainerType::reference (ContainerType::*backptr)(); typedef typename ContainerType::reference (ContainerType::*backptr)();
register_function(system, (backptr(&ContainerType::back)), "back"); m->add(fun(backptr(&ContainerType::back)), "back");
std::string push_back_name; std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
@@ -250,8 +317,9 @@ namespace dispatchkit
push_back_name = "push_back"; push_back_name = "push_back";
} }
register_function(system, &ContainerType::push_back, push_back_name); m->add(fun(&ContainerType::push_back), push_back_name);
register_function(system, &ContainerType::pop_back, "pop_back"); m->add(fun(&ContainerType::pop_back), "pop_back");
return m;
} }
/** /**
@@ -259,11 +327,12 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Vector.html * http://www.sgi.com/tech/stl/Vector.html
*/ */
template<typename VectorType> template<typename VectorType>
void bootstrap_vector(Dispatch_Engine &system, const std::string &type) ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_type<VectorType>(type); m->add(user_type<VectorType>(), type);
bootstrap_random_access_container<VectorType>(system, type); random_access_container_type<VectorType>(type, m);
bootstrap_back_insertion_sequence<VectorType>(system, type); back_insertion_sequence_type<VectorType>(type, m);
return m;
} }
/** /**
@@ -271,10 +340,11 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Vector.html * http://www.sgi.com/tech/stl/Vector.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_associative_container(Dispatch_Engine &system, const std::string &type) ModulePtr associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_forward_container<ContainerType>(system, type); forward_container_type<ContainerType>(type, m);
bootstrap_default_constructible<ContainerType>(system, type); default_constructible_type<ContainerType>(type, m);
return m;
} }
/** /**
@@ -282,17 +352,17 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/pair.html * http://www.sgi.com/tech/stl/pair.html
*/ */
template<typename PairType> template<typename PairType>
void bootstrap_pair(Dispatch_Engine &system, const std::string &type) ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_type<PairType>(type); m->add(user_type<PairType>(), type);
register_member(system, &PairType::first, "first"); m->add(fun(&PairType::first), "first");
register_member(system, &PairType::second, "second"); m->add(fun(&PairType::second), "second");
system.register_function(build_constructor<PairType >(), type); basic_constructors<PairType>(type, m);
system.register_function(build_constructor<PairType, const PairType &>(), type); m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
system.register_function(build_constructor<PairType, const PairType &>(), "clone");
system.register_function(build_constructor<PairType, const typename PairType::first_type &, const typename PairType::second_type &>(), type); return m;
} }
@@ -301,10 +371,12 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html * http://www.sgi.com/tech/stl/PairAssociativeContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_pair_associative_container(Dispatch_Engine &system, const std::string &type) ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_associative_container<ContainerType>(system, type); associative_container_type<ContainerType>(type, m);
bootstrap_pair<typename ContainerType::value_type>(system, type + "_Pair"); pair_type<typename ContainerType::value_type>(type + "_Pair", m);
return m;
} }
/** /**
@@ -312,10 +384,12 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html * http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_unique_associative_container(Dispatch_Engine &system, const std::string &type) ModulePtr unique_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_associative_container<ContainerType>(system, type); associative_container_type<ContainerType>(type, m);
register_function(system, &ContainerType::count, "count"); m->add(fun<size_t (ContainerType::*)(const typename ContainerType::key_type &) const>(&ContainerType::count), "count");
return m;
} }
/** /**
@@ -323,14 +397,16 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/SortedAssociativeContainer.html * http://www.sgi.com/tech/stl/SortedAssociativeContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_sorted_associative_container(Dispatch_Engine &system, const std::string &type) ModulePtr sorted_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator> typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator>
(ContainerType::*eq_range)(const typename ContainerType::key_type &); (ContainerType::*eq_range)(const typename ContainerType::key_type &);
bootstrap_reversible_container<ContainerType>(system, type); reversible_container_type<ContainerType>(type, m);
bootstrap_associative_container<ContainerType>(system, type); associative_container_type<ContainerType>(type, m);
register_function(system, eq_range(&ContainerType::equal_range), "equal_range"); m->add(fun(eq_range(&ContainerType::equal_range)), "equal_range");
return m;
} }
/** /**
@@ -338,10 +414,12 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/UniqueSortedAssociativeContainer.html * http://www.sgi.com/tech/stl/UniqueSortedAssociativeContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_unique_sorted_associative_container(Dispatch_Engine &system, const std::string &type) ModulePtr unique_sorted_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_sorted_associative_container<ContainerType>(system, type); sorted_associative_container_type<ContainerType>(type, m);
bootstrap_unique_associative_container<ContainerType>(system, type); unique_associative_container_type<ContainerType>(type, m);
return m;
} }
/** /**
@@ -349,12 +427,14 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/Map.html * http://www.sgi.com/tech/stl/Map.html
*/ */
template<typename MapType> template<typename MapType>
void bootstrap_map(Dispatch_Engine &system, const std::string &type) ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_type<MapType>(type); m->add(user_type<MapType>(), type);
register_function(system, &MapType::operator[], "[]"); m->add(fun(&MapType::operator[]), "[]");
bootstrap_unique_sorted_associative_container<MapType>(system, type); unique_sorted_associative_container_type<MapType>(type, m);
bootstrap_pair_associative_container<MapType>(system, type); pair_associative_container_type<MapType>(type, m);
return m;
} }
/** /**
@@ -362,21 +442,35 @@ namespace dispatchkit
* http://www.sgi.com/tech/stl/basic_string.html * http://www.sgi.com/tech/stl/basic_string.html
*/ */
template<typename String> template<typename String>
void bootstrap_string(Dispatch_Engine &system, const std::string &type) ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
system.register_type<String>(type); m->add(user_type<String>(), type);
add_oper_add<String>(system); oper_add<String>(m);
add_oper_add_equals<String>(system); oper_add_equals<String>(m);
add_opers_comparison<String>(system); opers_comparison<String>(m);
bootstrap_random_access_container<String>(system, type); random_access_container_type<String>(type, m);
bootstrap_sequence<String>(system, type); sequence_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations
std::string push_back_name;
if (typeid(typename String::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
m->add(fun(&String::push_back), push_back_name);
typedef typename String::size_type (String::*find_func)(const String &, typename String::size_type) const; typedef typename String::size_type (String::*find_func)(const String &, typename String::size_type) const;
register_function(system, find_func(&String::find), "find"); m->add(fun(find_func(&String::find)), "find");
register_function(system, find_func(&String::rfind), "rfind"); m->add(fun(find_func(&String::rfind)), "rfind");
register_function(system, find_func(&String::find_first_of), "find_first_of"); m->add(fun(find_func(&String::find_first_of)), "find_first_of");
register_function(system, find_func(&String::find_last_of), "find_last_of"); m->add(fun(find_func(&String::find_last_of)), "find_last_of");
register_function(system, find_func(&String::find_first_not_of), "find_first_not_of"); m->add(fun(find_func(&String::find_first_not_of)), "find_first_not_of");
register_function(system, find_func(&String::find_last_not_of), "find_last_not_of"); m->add(fun(find_func(&String::find_last_not_of)), "find_last_not_of");
return m;
}
} }
} }

View File

@@ -17,7 +17,7 @@
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_const.hpp>
namespace dispatchkit namespace chaiscript
{ {
/** /**
* Boxed_Value is the main tool of the dispatchkit. It allows * Boxed_Value is the main tool of the dispatchkit. It allows
@@ -97,11 +97,6 @@ namespace dispatchkit
return *this; return *this;
} }
static bool get_false()
{
return false;
}
Type_Info m_type_info; Type_Info m_type_info;
boost::any m_obj; boost::any m_obj;
bool m_is_ref; bool m_is_ref;
@@ -116,26 +111,37 @@ namespace dispatchkit
*/ */
struct Object_Cache struct Object_Cache
{ {
Object_Cache()
: m_cullcount(0)
{
}
boost::shared_ptr<Data> get(Boxed_Value::Void_Type) boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{ {
return boost::shared_ptr<Data> (new Data( return boost::shared_ptr<Data> (new Data(
Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
boost::any(), boost::any(),
false) false)
); );
} }
template<typename T> template<typename T>
boost::shared_ptr<Data> get(boost::shared_ptr<T> obj) boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
{
return get(*obj);
}
template<typename T>
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{ {
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
false, false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>())) boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
); );
std::map<void *, Data >::iterator itr std::map<const void *, Data>::iterator itr
= m_ptrs.find(obj.get()); = m_ptrs.find(obj.get());
if (itr != m_ptrs.end()) if (itr != m_ptrs.end())
@@ -148,19 +154,33 @@ namespace dispatchkit
return data; return data;
} }
template<typename T>
boost::shared_ptr<Data> get(T *t)
{
return get(boost::ref(*t));
}
template<typename T> template<typename T>
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj) boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{ {
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
true) true)
); );
std::map<void *, Data >::iterator itr std::map<const void *, Data >::iterator itr
= m_ptrs.find(obj.get_pointer()); = m_ptrs.find(obj.get_pointer());
if (itr != m_ptrs.end()) // If the ptr is found in the cache and it is the correct type,
// return it. It may be the incorrect type when two variables share the
// same memory location. Example:
// struct test { int x; };
// test t;
// Both t and t.x share the same memory location, but do not represent
// objects of the same type.
if (itr != m_ptrs.end()
&& itr->second.m_type_info.m_bare_type_info == data->m_type_info.m_bare_type_info)
{ {
(*data) = (itr->second); (*data) = (itr->second);
} }
@@ -172,7 +192,7 @@ namespace dispatchkit
boost::shared_ptr<Data> get(const T& t) boost::shared_ptr<Data> get(const T& t)
{ {
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(boost::shared_ptr<T>(new T(t))), boost::any(boost::shared_ptr<T>(new T(t))),
false, false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>())) boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
@@ -199,13 +219,19 @@ namespace dispatchkit
*/ */
void cull() void cull()
{ {
std::map<void *, Data >::iterator itr = m_ptrs.begin(); ++m_cullcount;
if (m_cullcount % 10 != 0)
{
return;
}
std::map<const void *, Data >::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end()) while (itr != m_ptrs.end())
{ {
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1) if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1)
{ {
std::map<void *, Data >::iterator todel = itr; std::map<const void *, Data >::iterator todel = itr;
++itr; ++itr;
m_ptrs.erase(todel); m_ptrs.erase(todel);
} else { } else {
@@ -214,7 +240,8 @@ namespace dispatchkit
} }
} }
std::map<void *, Data > m_ptrs; std::map<const void *, Data > m_ptrs;
int m_cullcount;
}; };
public: public:
@@ -304,6 +331,8 @@ namespace dispatchkit
}; };
namespace detail
{
// Cast_Helper helper classes // Cast_Helper helper classes
/** /**
@@ -317,8 +346,13 @@ namespace dispatchkit
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else { } else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get()))); return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
@@ -336,8 +370,13 @@ namespace dispatchkit
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else { } else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get()))); return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
@@ -355,8 +394,13 @@ namespace dispatchkit
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
{ {
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer(); return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else { } else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get(); return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} }
@@ -415,6 +459,21 @@ namespace dispatchkit
} }
}; };
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/** /**
* Cast_Helper for casting to a Boxed_Value type * Cast_Helper for casting to a Boxed_Value type
@@ -422,7 +481,7 @@ namespace dispatchkit
template<> template<>
struct Cast_Helper<Boxed_Value> struct Cast_Helper<Boxed_Value>
{ {
typedef Boxed_Value Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob)
{ {
@@ -436,13 +495,14 @@ namespace dispatchkit
template<> template<>
struct Cast_Helper<const Boxed_Value &> struct Cast_Helper<const Boxed_Value &>
{ {
typedef Boxed_Value Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob)
{ {
return ob; return ob;
} }
}; };
}
/** /**
* class that is thrown in the event of a bad_boxed_cast. That is, * class that is thrown in the event of a bad_boxed_cast. That is,
@@ -480,10 +540,10 @@ namespace dispatchkit
* int &i = boxed_cast<int &>(boxedvalue); * int &i = boxed_cast<int &>(boxedvalue);
*/ */
template<typename Type> template<typename Type>
typename Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
{ {
try { try {
return Cast_Helper<Type>::cast(bv); return detail::Cast_Helper<Type>::cast(bv);
} catch (const boost::bad_any_cast &) { } catch (const boost::bad_any_cast &) {
throw bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
@@ -619,6 +679,8 @@ namespace dispatchkit
bool m_isfloat; bool m_isfloat;
}; };
namespace detail
{
/** /**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/ */
@@ -632,6 +694,22 @@ namespace dispatchkit
return Boxed_POD_Value(ob); return Boxed_POD_Value(ob);
} }
}; };
}
template<typename T>
Boxed_Value var(T t)
{
return Boxed_Value(t);
}
/**
* Return true if the two Boxed_Values share the same internal type
*/
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
}
} }
#endif #endif

View File

@@ -23,22 +23,61 @@
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
namespace dispatchkit namespace chaiscript
{ {
class Module
{
public:
Module &add(const Type_Info &ti, const std::string &name)
{
m_typeinfos.push_back(std::make_pair(ti, name));
return *this;
}
Module &add(const Proxy_Function &f, const std::string &name)
{
m_funcs.push_back(std::make_pair(f, name));
return *this;
}
template<typename T>
void apply(T &t) const
{
apply(m_typeinfos.begin(), m_typeinfos.end(), t);
apply(m_funcs.begin(), m_funcs.end(), t);
}
private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
template<typename T, typename InItr>
void apply(InItr begin, InItr end, T &t) const
{
while (begin != end)
{
t.add(begin->first, begin->second);
++begin;
}
}
};
typedef boost::shared_ptr<Module> ModulePtr;
/** /**
* A Proxy_Function implementation that is able to take * A Proxy_Function implementation that is able to take
* a vector of Proxy_Functions and perform a dispatch on them. It is * a vector of Proxy_Functions and perform a dispatch on them. It is
* used specifically in the case of dealing with Function object variables * used specifically in the case of dealing with Function object variables
*/ */
class Dispatch_Function : public Proxy_Function class Dispatch_Function : public Proxy_Function_Base
{ {
public: public:
Dispatch_Function(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs) Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
: m_funcs(t_funcs) : m_funcs(t_funcs)
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
@@ -55,16 +94,21 @@ namespace dispatchkit
return std::vector<Type_Info>(); return std::vector<Type_Info>();
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual int get_arity() const
{ {
typedef std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > function_vec; return -1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = m_funcs.begin(); function_vec::const_iterator begin = m_funcs.begin();
function_vec::const_iterator end = m_funcs.end(); function_vec::const_iterator end = m_funcs.end();
while (begin != end) while (begin != end)
{ {
if (begin->second->types_match(types)) if (begin->second->call_match(vals))
{ {
return true; return true;
} else { } else {
@@ -81,7 +125,24 @@ namespace dispatchkit
} }
private: private:
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > m_funcs; std::vector<std::pair<std::string, Proxy_Function > > m_funcs;
};
/**
* Exception thrown in the case that a multi method dispatch fails
* because no matching function was found
* at runtime due to either an arity_error, a guard_error or a bad_boxed_cast
* exception
*/
struct reserved_word_error : std::runtime_error
{
reserved_word_error(const std::string &word) throw()
: std::runtime_error("Reserved word not allowed in object name: " + word)
{
}
virtual ~reserved_word_error() throw() {}
}; };
@@ -92,46 +153,47 @@ namespace dispatchkit
class Dispatch_Engine class Dispatch_Engine
{ {
public: public:
typedef std::map<std::string, dispatchkit::Type_Info> Type_Name_Map; typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope; typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> Stack; typedef boost::shared_ptr<std::deque<Scope> > Stack;
Dispatch_Engine() Dispatch_Engine()
: m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object())) : m_scopes(new Stack::element_type()),
m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
{ {
m_scopes.push_back(Scope()); m_scopes->push_back(Scope());
} }
/** /**
* Add a new named Proxy_Function to the system * Add a new named Proxy_Function to the system
*/ */
bool register_function(const boost::shared_ptr<Proxy_Function> &f, const std::string &name) bool add(const Proxy_Function &f, const std::string &name)
{ {
validate_object_name(name);
return add_function(f, name); return add_function(f, name);
} }
/** /**
* Add a generic, named boost::function() to the system * Add a module's worth of registrations to the system
*/ */
template<typename Function> void add(const ModulePtr &m)
bool register_function(const Function &func, const std::string &name)
{ {
return add_function(boost::shared_ptr<Proxy_Function>(new Proxy_Function_Impl<Function>(func)), name); m->apply(*this);
} }
/** /**
* Set the value of an object, by name. If the object * Set the value of an object, by name. If the object
* is not available in the current scope it is created * is not available in the current scope it is created
*/ */
template<typename Class> void add(const Boxed_Value &obj, const std::string &name)
void set_object(const std::string &name, const Class &obj)
{ {
for (int i = m_scopes.size()-1; i >= 0; --i) validate_object_name(name);
for (int i = m_scopes->size()-1; i >= 0; --i)
{ {
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name); std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != m_scopes[i].end()) if (itr != (*m_scopes)[i].end())
{ {
m_scopes[i][name] = Boxed_Value(obj); (*m_scopes)[i][name] = Boxed_Value(obj);
return; return;
} }
} }
@@ -142,10 +204,10 @@ namespace dispatchkit
/** /**
* Adds a named object to the current scope * Adds a named object to the current scope
*/ */
template<typename Class> void add_object(const std::string &name, const Boxed_Value &obj)
void add_object(const std::string &name, const Class &obj)
{ {
m_scopes.back()[name] = Boxed_Value(obj); validate_object_name(name);
m_scopes->back()[name] = Boxed_Value(obj);
} }
/** /**
@@ -153,7 +215,7 @@ namespace dispatchkit
*/ */
void new_scope() void new_scope()
{ {
m_scopes.push_back(Scope()); m_scopes->push_back(Scope());
} }
/** /**
@@ -161,9 +223,9 @@ namespace dispatchkit
*/ */
void pop_scope() void pop_scope()
{ {
if (m_scopes.size() > 1) if (m_scopes->size() > 1)
{ {
m_scopes.pop_back(); m_scopes->pop_back();
} else { } else {
throw std::range_error("Unable to pop global stack"); throw std::range_error("Unable to pop global stack");
} }
@@ -182,10 +244,16 @@ namespace dispatchkit
* \returns the old stack * \returns the old stack
* \param[in] s The new stack * \param[in] s The new stack
*/ */
Stack set_stack(Stack s) Stack set_stack(const Stack &s)
{ {
std::swap(s, m_scopes); Stack old = m_scopes;
return s; m_scopes = s;
return old;
}
Stack new_stack()
{
return Stack(new Stack::element_type());
} }
/** /**
@@ -200,32 +268,31 @@ namespace dispatchkit
return m_place_holder; return m_place_holder;
} }
for (int i = m_scopes.size()-1; i >= 0; --i) for (int i = m_scopes->size()-1; i >= 0; --i)
{ {
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name); std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != m_scopes[i].end()) if (itr != (*m_scopes)[i].end())
{ {
return itr->second; return itr->second;
} }
} }
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > funcs = get_function_impl(name, false); std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
if (funcs.empty()) if (funcs.empty())
{ {
throw std::range_error("Object not known: " + name); throw std::range_error("Object not known: " + name);
} else { } else {
return Boxed_Value(boost::shared_ptr<Proxy_Function>(new Dispatch_Function(funcs))); return Boxed_Value(Proxy_Function(new Dispatch_Function(funcs)));
} }
} }
/** /**
* Registers a new named type * Registers a new named type
*/ */
template<typename Type> void add(const Type_Info &ti, const std::string &name)
void register_type(const std::string &name)
{ {
m_types.insert(std::make_pair(name, Get_Type_Info<Type>::get())); m_types.insert(std::make_pair(name, ti));
} }
/** /**
@@ -274,59 +341,57 @@ namespace dispatchkit
/** /**
* Return a function by name * Return a function by name
*/ */
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
get_function(const std::string &t_name) const get_function(const std::string &t_name) const
{ {
return get_function_impl(t_name, true); std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_functions.equal_range(t_name);
return std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
}
/**
* Return true if a function exists
*/
bool function_exists(const std::string &name) const
{
return m_functions.find(name) != m_functions.end();
} }
/** /**
* Get a vector of all registered functions * Get a vector of all registered functions
*/ */
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > get_functions() const std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
{ {
return std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >(m_functions.begin(), m_functions.end()); return std::vector<std::pair<std::string, Proxy_Function > >(m_functions.begin(), m_functions.end());
} }
void add_reserved_word(const std::string &name)
{
m_reserved_words.insert(name);
}
private: private:
/** /**
* Implementation detail for searching for a function by name. * Throw a reserved_word exception if the name is not allowed
* Looks for all registered global functions and optionally for an object
* in scope with the same name
*/ */
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > void validate_object_name(const std::string &name)
get_function_impl(const std::string &t_name, bool include_objects) const
{ {
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > funcs; if (m_reserved_words.find(name) != m_reserved_words.end())
if (include_objects)
{ {
try { throw reserved_word_error(name);
funcs.insert(funcs.end(),
std::make_pair(
t_name,
boxed_cast<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type>(get_object(t_name)))
);
} catch (const bad_boxed_cast &) {
} catch (const std::range_error &) {
} }
} }
std::pair<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator> range
= m_functions.equal_range(t_name);
funcs.insert(funcs.end(), range.first, range.second);
return funcs;
}
/** /**
* Implementation detail for adding a function. Returns * Implementation detail for adding a function. Returns
* true if the function was added, false if a function with the * true if the function was added, false if a function with the
* same signature and name already exists. * same signature and name already exists.
*/ */
bool add_function(const boost::shared_ptr<Proxy_Function> &f, const std::string &t_name) bool add_function(const Proxy_Function &f, const std::string &t_name)
{ {
std::pair<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator> range std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_functions.equal_range(t_name); = m_functions.equal_range(t_name);
while (range.first != range.second) while (range.first != range.second)
@@ -342,11 +407,12 @@ namespace dispatchkit
return true; return true;
} }
std::deque<Scope> m_scopes; Stack m_scopes;
std::multimap<std::string, boost::shared_ptr<Proxy_Function> > m_functions; std::multimap<std::string, Proxy_Function > m_functions;
Type_Name_Map m_types; Type_Name_Map m_types;
Boxed_Value m_place_holder; Boxed_Value m_place_holder;
std::set<std::string> m_reserved_words;
}; };
/** /**
@@ -354,7 +420,8 @@ namespace dispatchkit
*/ */
void dump_object(Boxed_Value o, const Dispatch_Engine &e) void dump_object(Boxed_Value o, const Dispatch_Engine &e)
{ {
std::cout << e.get_type_name(o.get_type_info()) << std::endl; Type_Info ti = o.get_type_info();
std::cout << (ti.m_is_const?"const ":"") << e.get_type_name(ti) << std::endl;
} }
/** /**
@@ -362,13 +429,13 @@ namespace dispatchkit
*/ */
void dump_type(const Type_Info &type, const Dispatch_Engine &e) void dump_type(const Type_Info &type, const Dispatch_Engine &e)
{ {
std::cout << e.get_type_name(type); std::cout << (type.m_is_const?"const ":"") << e.get_type_name(type);
} }
/** /**
* Dump function to stdout * Dump function to stdout
*/ */
void dump_function(const std::pair<const std::string, boost::shared_ptr<Proxy_Function> > &f, const Dispatch_Engine &e) void dump_function(const std::pair<const std::string, Proxy_Function > &f, const Dispatch_Engine &e)
{ {
std::vector<Type_Info> params = f.second->get_param_types(); std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation(); std::string annotation = f.second->annotation();
@@ -412,10 +479,10 @@ namespace dispatchkit
} }
std::cout << std::endl; std::cout << std::endl;
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > funcs = s.get_functions(); std::vector<std::pair<std::string, Proxy_Function > > funcs = s.get_functions();
std::cout << "Functions: " << std::endl; std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin(); for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
itr != funcs.end(); itr != funcs.end();
++itr) ++itr)
{ {
@@ -423,6 +490,24 @@ namespace dispatchkit
} }
std::cout << std::endl; std::cout << std::endl;
} }
/**
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(const Dispatch_Engine &e, const std::string &user_typename, Boxed_Value r)
{
try {
return e.get_type(user_typename) == r.get_type_info();
} catch (const std::range_error &) {
return false;
}
}
std::string type_name(const Dispatch_Engine &e, Boxed_Value obj)
{
return e.get_type_name(obj.get_type_info());
}
} }
#endif #endif

View File

@@ -4,13 +4,6 @@
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_hpp__ #ifndef __function_call_hpp__
#define __function_call_hpp__ #define __function_call_hpp__
@@ -20,52 +13,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "function_call_detail.hpp"
namespace dispatchkit namespace chaiscript
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
class Function_Caller_Ret
{
public:
Function_Caller_Ret()
{
}
Ret call(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
class Function_Caller_Ret<void>
{
public:
Function_Caller_Ret()
{
}
void call(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call.hpp>
#include BOOST_PP_ITERATE()
namespace dispatchkit
{ {
/** /**
* Build a function caller that knows how to dispatch on a set of functions * Build a function caller that knows how to dispatch on a set of functions
@@ -77,10 +27,10 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs) functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
{ {
FunctionType *p; FunctionType *p=0;
return build_function_caller_helper(p, funcs); return detail::build_function_caller_helper(p, funcs);
} }
/** /**
@@ -88,7 +38,7 @@ namespace dispatchkit
* useful in the case that a function is being pass out from scripting back * useful in the case that a function is being pass out from scripting back
* into code * into code
* example: * example:
* void my_function(boost::shared_ptr<Proxy_Function> f) * void my_function(Proxy_Function f)
* { * {
* boost::function<void (int)> local_f = * boost::function<void (int)> local_f =
* build_function_caller(f); * build_function_caller(f);
@@ -98,11 +48,11 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(boost::shared_ptr<Proxy_Function> func) functor(Proxy_Function func)
{ {
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > funcs; std::vector<std::pair<std::string, Proxy_Function > > funcs;
funcs.push_back(std::make_pair(std::string(), func)); funcs.push_back(std::make_pair(std::string(), func));
return build_function_caller<FunctionType>(funcs); return functor<FunctionType>(funcs);
} }
/** /**
@@ -111,58 +61,11 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(const Boxed_Value &bv) functor(const Boxed_Value &bv)
{ {
return build_function_caller<FunctionType>(boxed_cast<boost::shared_ptr<Proxy_Function> >(bv)); return functor<FunctionType>(boxed_cast<Proxy_Function >(bv));
} }
/**
* Helper for calling script code as if it were native C++ code
* example:
* boost::function<int (int, int)> f = build_functor(chai, "func(x, y){x+y}");
* \return a boost::function representing the passed in script
* \param[in] e ScriptEngine to build the script execution from
* \param[in] script Script code to build a function from
*/
template<typename FunctionType, typename ScriptEngine>
boost::function<FunctionType> build_functor(ScriptEngine &e, const std::string &script)
{
return build_function_caller<FunctionType>(e.evaluate_string(script));
}
}
# endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>().call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
} }
#endif #endif

View File

@@ -0,0 +1,98 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(boost::is_reference<Param ## n>::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_detail_hpp__
#define __function_call_detail_hpp__
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>
#include <vector>
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
struct Function_Caller_Ret
{
static Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void>
{
static void call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace detail
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, Proxy_Function > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>::call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Proxy_Function> > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
}
}
#endif

View File

@@ -0,0 +1,100 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#ifndef __handle_return_hpp__
#define __handle_return_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
static Boxed_Value call(const boost::function<Ret ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<const boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value call(const boost::function<Ret &()> &f)
{
return Boxed_Value(boost::ref(f()));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value call(const boost::function<Boxed_Value ()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
static Boxed_Value call(const boost::function<Boxed_Value &()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value call(const boost::function<void ()> &f)
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};
}
#endif

View File

@@ -19,17 +19,30 @@
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp> #define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp>
#include BOOST_PP_ITERATE() #include BOOST_PP_ITERATE()
# endif # endif
namespace chaiscript
{
template<typename T>
Proxy_Function constructor()
{
T *f = 0;
return (detail::build_constructor_(f));
}
}
#else #else
# define n BOOST_PP_ITERATION() # define n BOOST_PP_ITERATION()
namespace dispatchkit namespace chaiscript
{ {
namespace detail
{
/** /**
* A constructor function, used for creating a new object * A constructor function, used for creating a new object
* of a given type with a given set of params * of a given type with a given set of params
*/ */
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) > template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{ {
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) )); return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
} }
@@ -41,10 +54,11 @@ namespace dispatchkit
* \todo See if it is possible to make this not be a variadic function * \todo See if it is possible to make this not be a variadic function
*/ */
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) > template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<boost::shared_ptr<Class> (BOOST_PP_ENUM_PARAMS(n, Param))> build_constructor() Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
typedef boost::shared_ptr<Class> (*func)(BOOST_PP_ENUM_PARAMS(n, Param)); typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return boost::function<boost::shared_ptr<Class> (BOOST_PP_ENUM_PARAMS(n, Param))>(func(&(constructor<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))); return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
} }
} }

View File

@@ -4,98 +4,29 @@
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) dispatchkit::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_hpp__ #ifndef __proxy_functions_hpp__
#define __proxy_functions_hpp__ #define __proxy_functions_hpp__
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include <string> #include <string>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include "proxy_functions_detail.hpp"
namespace dispatchkit namespace chaiscript
{ {
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
Boxed_Value operator()(const boost::function<Ret ()> &f)
{
return Boxed_Value(f());
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
Boxed_Value operator()(const boost::function<Ret &()> &f)
{
return Boxed_Value(boost::ref(f()));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
Boxed_Value operator()(const boost::function<void ()> &f)
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};
/** /**
* Helper for building a list of parameters for calling a Proxy_Function * Helper for building a list of parameters for calling a Proxy_Function
* it does automatic conversion to Boxed_Value types via operator<< * it does automatic conversion to Boxed_Value types via operator<<
* *
* example usage: * example usage:
* Boxed_Value retval = dispatch(dispatchengine.get_function("+"), * Boxed_Value retval = dispatch(dispatchengine.get_function("+"),
* dispatchkit::Param_List_Builder() << 5 << 6); * chaiscript::Param_List_Builder() << 5 << 6);
*/ */
struct Param_List_Builder struct Param_List_Builder
{ {
@@ -120,30 +51,6 @@ namespace dispatchkit
std::vector<Boxed_Value> objects; std::vector<Boxed_Value> objects;
}; };
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions.hpp>
#include BOOST_PP_ITERATE()
namespace dispatchkit
{
/** /**
* Pure virtual base class for all Proxy_Function implementations * Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++ * Proxy_Functions are a type erasure of type safe C++
@@ -152,17 +59,60 @@ namespace dispatchkit
* Dispatch_Engine only knows how to work with Proxy_Function, no other * Dispatch_Engine only knows how to work with Proxy_Function, no other
* function classes. * function classes.
*/ */
class Proxy_Function class Proxy_Function_Base
{ {
public: public:
virtual ~Proxy_Function() {} virtual ~Proxy_Function_Base() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0; virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0;
virtual std::vector<Type_Info> get_param_types() const = 0; virtual std::vector<Type_Info> get_param_types() const = 0;
virtual bool operator==(const Proxy_Function &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool types_match(const std::vector<Boxed_Value> &types) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
//! Return true if the function is a possible match
//! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals) const
{
int arity = get_arity();
if (arity < 0)
{
return true;
} else if (size_t(arity) == vals.size()) {
if (arity == 0)
{
return true;
} else {
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
if (!ti.m_bare_type_info || !(vals[0].get_type_info().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_Value>().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_POD_Value>().m_bare_type_info)
|| (*vals[0].get_type_info().m_bare_type_info) == (*ti.m_bare_type_info))
{
return true;
} else {
return false;
}
}
} else {
return false;
}
}
virtual int get_arity() const = 0;
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
}; };
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
/** /**
* Exception thrown if a function's guard fails to execute * Exception thrown if a function's guard fails to execute
*/ */
@@ -181,27 +131,28 @@ namespace dispatchkit
* A Proxy_Function implementation that is not type safe, the called function * 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. * is expecting a vector<Boxed_Value> that it works with how it chooses.
*/ */
class Dynamic_Proxy_Function : public Proxy_Function class Dynamic_Proxy_Function : public Proxy_Function_Base
{ {
public: public:
Dynamic_Proxy_Function( Dynamic_Proxy_Function(
const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f, const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
int t_arity=-1, int t_arity=-1,
const std::string &t_description = "", const std::string &t_description = "",
const boost::shared_ptr<Proxy_Function> &t_guard = boost::shared_ptr<Proxy_Function>()) const Proxy_Function &t_guard = Proxy_Function())
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard) : m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard),
m_types(build_param_type_list(t_arity))
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
return (m_arity < 0 || types.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(types); && test_guard(vals);
} }
virtual ~Dynamic_Proxy_Function() {} virtual ~Dynamic_Proxy_Function() {}
@@ -223,23 +174,14 @@ namespace dispatchkit
} }
} }
virtual int get_arity() const
{
return m_arity;
}
virtual std::vector<Type_Info> get_param_types() const virtual std::vector<Type_Info> get_param_types() const
{ {
std::vector<Type_Info> types; return m_types;
types.push_back(Get_Type_Info<Boxed_Value>::get());
if (m_arity >= 0)
{
for (int i = 0; i < m_arity; ++i)
{
types.push_back(Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
} }
virtual std::string annotation() const virtual std::string annotation() const
@@ -264,10 +206,30 @@ namespace dispatchkit
} }
} }
static std::vector<Type_Info> build_param_type_list(int arity)
{
std::vector<Type_Info> types;
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
if (arity >= 0)
{
for (int i = 0; i < arity; ++i)
{
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(detail::Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
}
boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f; boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity; int m_arity;
std::string m_description; std::string m_description;
boost::shared_ptr<Proxy_Function> m_guard; Proxy_Function m_guard;
std::vector<Type_Info> m_types;
}; };
/** /**
@@ -284,26 +246,25 @@ namespace dispatchkit
* at runtime, when call() is executed. * at runtime, when call() is executed.
* it is used for bind(function, param1, _, param2) style calls * it is used for bind(function, param1, _, param2) style calls
*/ */
class Bound_Function : public Proxy_Function class Bound_Function : public Proxy_Function_Base
{ {
public: public:
Bound_Function(const boost::shared_ptr<Proxy_Function> &t_f, Bound_Function(const Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) const std::vector<Boxed_Value> &t_args)
: m_f(t_f), m_args(t_args) : m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
std::vector<Boxed_Value> params = build_param_list(types); return m_f->call_match(build_param_list(vals));
return m_f->types_match(params);
} }
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
@@ -323,7 +284,7 @@ namespace dispatchkit
while (true) while (true)
{ {
while (barg != m_args.end() while (barg != m_args.end()
&& !(barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get())) && !(barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get()))
{ {
args.push_back(*barg); args.push_back(*barg);
++barg; ++barg;
@@ -336,7 +297,7 @@ namespace dispatchkit
} }
if (barg != m_args.end() if (barg != m_args.end()
&& barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get()) && barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get())
{ {
++barg; ++barg;
} }
@@ -354,14 +315,20 @@ namespace dispatchkit
return std::vector<Type_Info>(); return std::vector<Type_Info>();
} }
virtual int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const virtual std::string annotation() const
{ {
return ""; return "";
} }
private: private:
boost::shared_ptr<Proxy_Function> m_f; Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity;
}; };
/** /**
@@ -370,17 +337,17 @@ namespace dispatchkit
* type checking of Boxed_Value parameters, in a type safe manner * type checking of Boxed_Value parameters, in a type safe manner
*/ */
template<typename Func> template<typename Func>
class Proxy_Function_Impl : public Proxy_Function class Proxy_Function_Impl : public Proxy_Function_Base
{ {
public: public:
Proxy_Function_Impl(const Func &f) Proxy_Function_Impl(const boost::function<Func> &f)
: m_f(f) : m_f(f), m_dummy_func(0), m_types(build_param_type_list(m_dummy_func))
{ {
} }
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
virtual bool operator==(const Proxy_Function &t_func) const virtual bool operator==(const Proxy_Function_Base &t_func) const
{ {
try { try {
dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func); dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func);
@@ -397,12 +364,18 @@ namespace dispatchkit
virtual std::vector<Type_Info> get_param_types() const virtual std::vector<Type_Info> get_param_types() const
{ {
return build_param_type_list(m_f); return m_types;
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual int get_arity() const
{ {
return compare_types(m_f, types); return m_types.size() - 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
return compare_types(m_dummy_func, vals);
} }
virtual std::string annotation() const virtual std::string annotation() const
@@ -411,7 +384,9 @@ namespace dispatchkit
} }
private: private:
Func m_f; boost::function<Func> m_f;
Func *m_dummy_func;
std::vector<Type_Info> m_types;
}; };
/** /**
@@ -435,15 +410,18 @@ namespace dispatchkit
* each function against the set of parameters, in order, until a matching * each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found * function is found or throw dispatch_error if no matching function is found
*/ */
Boxed_Value dispatch(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs, Boxed_Value dispatch(const std::vector<std::pair<std::string, Proxy_Function> > &funcs,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist)
{ {
for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin(); for (std::vector<std::pair<std::string, Proxy_Function> >::const_iterator itr = funcs.begin();
itr != funcs.end(); itr != funcs.end();
++itr) ++itr)
{ {
try { try {
if (itr->second->filter(plist))
{
return (*itr->second)(plist); return (*itr->second)(plist);
}
} catch (const bad_boxed_cast &) { } catch (const bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
} catch (const arity_error &) { } catch (const arity_error &) {
@@ -457,70 +435,5 @@ namespace dispatchkit
} }
} }
# endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &)
{
std::vector<Type_Info> ti;
ti.push_back(Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter 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 Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
}
#endif #endif

View File

@@ -0,0 +1,121 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,chaiscript::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((detail::Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_detail_hpp__
#define __proxy_functions_detail_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
std::vector<Type_Info> ti;
ti.push_back(detail::Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter 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 Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>::call(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
}
#endif

View File

@@ -14,15 +14,23 @@
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
namespace dispatchkit namespace chaiscript
{ {
namespace detail
{
/** /**
* Helper function for register_member function * Helper function for register_member function
*/ */
template<typename T, typename Class> template<typename T, typename Class>
T &get_member(T Class::* m, Class *obj) T &get_member(T Class::* m, Class *obj)
{ {
return obj->*m; return (obj->*m);
}
template<typename T>
Proxy_Function fun_helper(const boost::function<T> &f)
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
} }
/** /**
@@ -31,9 +39,10 @@ namespace dispatchkit
* for example, the case of std::pair<>::first and std::pair<>::second * for example, the case of std::pair<>::first and std::pair<>::second
*/ */
template<typename T, typename Class> template<typename T, typename Class>
void register_member(Dispatch_Engine &s, T Class::* m, const std::string &name) Proxy_Function fun_helper(T Class::* m)
{ {
s.register_function(boost::function<T (Class *)>(boost::bind(&get_member<T, Class>, m, _1)), name); return fun_helper(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
}
} }
} }
@@ -41,37 +50,51 @@ namespace dispatchkit
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp> #define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp>
#include BOOST_PP_ITERATE() #include BOOST_PP_ITERATE()
namespace chaiscript
{
template<typename T>
Proxy_Function fun(T t)
{
return detail::fun_helper(t);
}
}
# endif # endif
#else #else
# define n BOOST_PP_ITERATION() # define n BOOST_PP_ITERATION()
namespace dispatchkit namespace chaiscript
{ {
namespace detail
{
/** /**
* Register a global function of n parameters with name * Register a global function of n parameters with name
*/ */
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const std::string &name) Proxy_Function fun_helper(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
s.register_function(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f), name); return fun_helper(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f));
} }
/** /**
* Register a class method of n parameters with name * Register a class method of n parameters with name
*/ */
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const std::string &name) Proxy_Function fun_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
s.register_function(boost::function<Ret (Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f), name); return fun_helper(boost::function<Ret (Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
} }
/** /**
* Register a const class method of n parameters with name * Register a const class method of n parameters with name
*/ */
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const std::string &name) Proxy_Function fun_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const)
{ {
s.register_function(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f), name); return fun_helper(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
}
} }
} }

View File

@@ -16,7 +16,7 @@
#include <boost/type_traits/remove_pointer.hpp> #include <boost/type_traits/remove_pointer.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
namespace dispatchkit namespace chaiscript
{ {
/** /**
* compile time deduced information about a type * compile time deduced information about a type
@@ -77,6 +77,8 @@ namespace dispatchkit
bool m_is_unknown; bool m_is_unknown;
}; };
namespace detail
{
/** /**
* Helper used to create a Type_Info object * Helper used to create a Type_Info object
*/ */
@@ -104,6 +106,18 @@ namespace dispatchkit
} }
}; };
template<typename T>
struct Get_Type_Info<const boost::shared_ptr<T> &>
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(const boost::shared_ptr<T> &),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T> template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> > struct Get_Type_Info<boost::reference_wrapper<T> >
{ {
@@ -115,6 +129,22 @@ namespace dispatchkit
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type)); &typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
} }
}; };
}
template<typename T>
Type_Info user_type(T)
{
return detail::Get_Type_Info<T>::get();
}
template<typename T>
Type_Info user_type()
{
return detail::Get_Type_Info<T>::get();
}
} }
#endif #endif

View File

@@ -19,13 +19,101 @@ namespace chaiscript
template <typename Eval_Engine> template <typename Eval_Engine>
class ChaiScript_System { class ChaiScript_System {
Eval_Engine engine; Eval_Engine engine;
std::set<std::string> loaded_files;
ChaiScript_Parser parser; ChaiScript_Parser parser;
/**
* Evaluates the given string in by parsing it and running the results through the evaluator
*/
Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__") {
//debug_print(tokens);
Boxed_Value value;
parser.clear_match_stack();
// Keep a cache of all loaded filenames and use the char * from this cache to pass
// to the parser. This is so that the parser does not have the overhead of passing
// around and copying strings
loaded_files.insert(filename);
try {
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
return value;
}
/**
* Evaluates the given boxed string, used during eval() inside of a script
*/
const Boxed_Value internal_eval(const std::vector<Boxed_Value> &vals) {
return do_eval(boxed_cast<std::string>(vals.at(0)));
}
void use(const std::string &filename)
{
if (loaded_files.count(filename) == 0)
{
eval_file(filename);
}
}
public: public:
ChaiScript_System() { ChaiScript_System() {
build_eval_system(); build_eval_system();
} }
/**
* Adds an object to the system: type, function, object
*/
template<typename T>
ChaiScript_System &add(const T &t, const std::string &name)
{
engine.add(t, name);
return *this;
}
/**
* Adds a module object to the system
*/
ChaiScript_System &add(const ModulePtr &p)
{
engine.add(p);
return *this;
}
/**
* Helper for calling script code as if it were native C++ code
* example:
* boost::function<int (int, int)> f = build_functor(chai, "func(x, y){x+y}");
* \return a boost::function representing the passed in script
* \param[in] script Script code to build a function from
*/
template<typename FunctionType>
boost::function<FunctionType> functor(const std::string &script)
{
return chaiscript::functor<FunctionType>(eval(script));
}
/**
* Evaluate a string via eval method
*/
Boxed_Value operator()(const std::string &script)
{
return do_eval(script);
}
/** /**
* Returns the current evaluation engine * Returns the current evaluation engine
*/ */
@@ -43,25 +131,14 @@ namespace chaiscript
} }
} }
/**
* Evaluates the given boxed string, used during eval() inside of a script
*/
const dispatchkit::Boxed_Value eval(const std::vector<dispatchkit::Boxed_Value> &vals) {
std::string val;
val = dispatchkit::boxed_cast<std::string &>(vals[0]);
return evaluate_string(val);
}
/** /**
* Helper function for loading a file * Helper function for loading a file
*/ */
std::string load_file(const char *filename) { std::string load_file(const std::string &filename) {
std::ifstream infile (filename, std::ios::in | std::ios::ate); std::ifstream infile (filename.c_str(), std::ios::in | std::ios::ate);
if (!infile.is_open()) { if (!infile.is_open()) {
std::string fname = filename; throw std::runtime_error("Can not open: " + filename);
throw std::runtime_error("Can not open: " + fname);
} }
std::streampos size = infile.tellg(); std::streampos size = infile.tellg();
@@ -79,48 +156,78 @@ namespace chaiscript
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
*/ */
void build_eval_system() { void build_eval_system() {
dispatchkit::Bootstrap::bootstrap(engine); using namespace bootstrap;
dispatchkit::bootstrap_vector<std::vector<dispatchkit::Boxed_Value> >(engine, "Vector"); engine.add_reserved_word("def");
dispatchkit::bootstrap_string<std::string>(engine, "string"); engine.add_reserved_word("fun");
dispatchkit::bootstrap_map<std::map<std::string, dispatchkit::Boxed_Value> >(engine, "Map"); engine.add_reserved_word("while");
dispatchkit::bootstrap_pair<std::pair<dispatchkit::Boxed_Value, dispatchkit::Boxed_Value > >(engine, "Pair"); engine.add_reserved_word("for");
engine.add_reserved_word("if");
engine.add_reserved_word("else");
engine.add_reserved_word("&&");
engine.add_reserved_word("||");
engine.add_reserved_word(",");
engine.add_reserved_word(":=");
engine.add_reserved_word("var");
engine.add_reserved_word("return");
engine.add_reserved_word("break");
engine.add_reserved_word("true");
engine.add_reserved_word("false");
engine.add_reserved_word("_");
engine.register_function(boost::shared_ptr<dispatchkit::Proxy_Function>(
new dispatchkit::Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::eval, boost::ref(*this), _1), 1)), "eval");
evaluate_string(chaiscript_prelude); engine.add(Bootstrap::bootstrap());
engine.add(fun(boost::function<void ()>(boost::bind(&dump_system, boost::ref(engine)))), "dump_system");
engine.add(fun(boost::function<void (Boxed_Value)>(boost::bind(&dump_object, _1, boost::ref(engine)))), "dump_object");
engine.add(fun(boost::function<bool (Boxed_Value, const std::string &)>(boost::bind(&is_type, boost::ref(engine), _2, _1))),
"is_type");
engine.add(fun(boost::function<std::string (Boxed_Value)>(boost::bind(&chaiscript::type_name, boost::ref(engine), _1))),
"type_name");
engine.add(fun(boost::function<bool (const std::string &)>(boost::bind(&Eval_Engine::function_exists, boost::ref(engine), _1))),
"function_exists");
engine.add(vector_type<std::vector<Boxed_Value> >("Vector"));
engine.add(string_type<std::string>("string"));
engine.add(map_type<std::map<std::string, Boxed_Value> >("Map"));
engine.add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
engine.add(fun(boost::function<void (const std::string &)>(boost::bind(&ChaiScript_System<Eval_Engine>::use, this, _1))), "use");
engine.add(Proxy_Function(
new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::internal_eval, boost::ref(*this), _1), 1)), "eval");
do_eval(chaiscript_prelude, "standard prelude");
} }
/** template<typename T>
* Evaluates the given string in by parsing it and running the results through the evaluator T eval(const std::string &input)
*/ {
dispatchkit::Boxed_Value evaluate_string(const std::string &input, const char *filename = "__EVAL__") { return boxed_cast<T>(do_eval(input));
//debug_print(tokens);
dispatchkit::Boxed_Value value;
parser.clear_match_stack();
try {
if (parser.parse(input, filename)) {
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
} }
return value; Boxed_Value eval(const std::string &input)
{
return do_eval(input);
} }
/** /**
* Loads the file specified by filename, evaluates it, and returns the result * Loads the file specified by filename, evaluates it, and returns the result
*/ */
dispatchkit::Boxed_Value evaluate_file(const char *filename) { Boxed_Value eval_file(const std::string &filename) {
return evaluate_string(load_file(filename), filename); return do_eval(load_file(filename), filename);
}
/**
* Loads the file specified by filename, evaluates it, and returns the as the specified type
*/
template<typename T>
T eval_file(const std::string &filename) {
return boxed_cast<T>(do_eval(load_file(filename), filename));
} }
}; };
typedef ChaiScript_System<dispatchkit::Dispatch_Engine> ChaiScript_Engine; typedef ChaiScript_System<Dispatch_Engine> ChaiScript;
} }
#endif /* CHAISCRIPT_ENGINE_HPP_ */ #endif /* CHAISCRIPT_ENGINE_HPP_ */

View File

@@ -15,14 +15,14 @@ namespace chaiscript
* Helper function that will set up the scope around a function call, including handling the named function parameters * Helper function that will set up the scope around a function call, including handling the named function parameters
*/ */
template <typename Eval_System> template <typename Eval_System>
const dispatchkit::Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector<std::string> &param_names, const std::vector<dispatchkit::Boxed_Value> &vals) { const Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector<std::string> &param_names, const std::vector<Boxed_Value> &vals) {
ss.new_scope(); ss.new_scope();
for (unsigned int i = 0; i < param_names.size(); ++i) { for (unsigned int i = 0; i < param_names.size(); ++i) {
ss.add_object(param_names[i], vals[i]); ss.add_object(param_names[i], vals[i]);
} }
dispatchkit::Boxed_Value retval; Boxed_Value retval;
try { try {
retval = eval_token(ss, node); retval = eval_token(ss, node);
@@ -42,8 +42,8 @@ namespace chaiscript
* Evaluates the top-level file node * Evaluates the top-level file node
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_file(Eval_System &ss, TokenPtr node) { Boxed_Value eval_file(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
for (i = 0; i < node->children.size(); ++i) { for (i = 0; i < node->children.size(); ++i) {
retval = eval_token(ss, node->children[i]); retval = eval_token(ss, node->children[i]);
@@ -55,13 +55,13 @@ namespace chaiscript
* Evaluates a variable or function name identifier * Evaluates a variable or function name identifier
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_id(Eval_System &ss, TokenPtr node) { Boxed_Value eval_id(Eval_System &ss, TokenPtr node) {
if (node->text == "true") { if (node->text == "true") {
return dispatchkit::Boxed_Value(true); return Boxed_Value(true);
} }
else if (node->text == "false") { else if (node->text == "false") {
return dispatchkit::Boxed_Value(false); return Boxed_Value(false);
} }
else { else {
try { try {
@@ -77,68 +77,73 @@ namespace chaiscript
* Evaluates a floating point number * Evaluates a floating point number
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_float(Eval_System &, TokenPtr node) { Boxed_Value eval_float(Eval_System &, TokenPtr node) {
return dispatchkit::Boxed_Value(double(atof(node->text.c_str()))); return Boxed_Value(double(atof(node->text.c_str())));
} }
/** /**
* Evaluates an integer * Evaluates an integer
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_int(Eval_System &, TokenPtr node) { Boxed_Value eval_int(Eval_System &, TokenPtr node) {
return dispatchkit::Boxed_Value(atoi(node->text.c_str())); return Boxed_Value(atoi(node->text.c_str()));
} }
/** /**
* Evaluates a quoted string * Evaluates a quoted string
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_quoted_string(Eval_System &, TokenPtr node) { Boxed_Value eval_quoted_string(Eval_System &, TokenPtr node) {
return dispatchkit::Boxed_Value(node->text); return Boxed_Value(node->text);
} }
/** /**
* Evaluates a char group * Evaluates a char group
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_single_quoted_string(Eval_System &, TokenPtr node) { Boxed_Value eval_single_quoted_string(Eval_System &, TokenPtr node) {
return dispatchkit::Boxed_Value(node->text); if (node->text.size() == 1) {
return Boxed_Value(char(node->text[0]));
}
else {
return Boxed_Value(char((int)node->text[0] * 0xff + (int)node->text[0]));
}
} }
/** /**
* Evaluates a string of equations in reverse order so that the right-most side has precedence * Evaluates a string of equations in reverse order so that the right-most side has precedence
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_equation(Eval_System &ss, TokenPtr node) { Boxed_Value eval_equation(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
retval = eval_token(ss, node->children.back()); retval = eval_token(ss, node->children.back());
if (node->children.size() > 1) { if (node->children.size() > 1) {
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) { for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
if (node->children[i+1]->text == "=") { if (node->children[i+1]->text == "=") {
dispatchkit::Boxed_Value lhs = eval_token(ss, node->children[i]); Boxed_Value lhs = eval_token(ss, node->children[i]);
try { try {
if (lhs.is_unknown()) if (lhs.is_unknown())
{ {
retval = dispatch(ss.get_function("clone"), dispatchkit::Param_List_Builder() << retval); retval = dispatch(ss.get_function("clone"), Param_List_Builder() << retval);
} }
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << lhs; plb << lhs;
plb << retval; plb << retval;
try { try {
retval = dispatch(ss.get_function(node->children[i+1]->text), plb); retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
} }
catch(const dispatchkit::dispatch_error &){ catch(const dispatch_error &){
throw Eval_Error("Mismatched types in equation", node->children[i+1]); throw Eval_Error("Mismatched types in equation", node->children[i+1]);
} }
} }
catch(const dispatchkit::dispatch_error &){ catch(const dispatch_error &){
throw Eval_Error("Can not clone right hand side of equation", node->children[i+1]); throw Eval_Error("Can not clone right hand side of equation", node->children[i+1]);
} }
} }
else if (node->children[i+1]->text == ":=") { else if (node->children[i+1]->text == ":=") {
dispatchkit::Boxed_Value lhs = eval_token(ss, node->children[i]); Boxed_Value lhs = eval_token(ss, node->children[i]);
if (lhs.is_unknown() || dispatchkit::Bootstrap::type_match(lhs, retval)) { if (lhs.is_unknown() || type_match(lhs, retval)) {
lhs.assign(retval); lhs.assign(retval);
} }
else { else {
@@ -146,13 +151,13 @@ namespace chaiscript
} }
} }
else { else {
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << eval_token(ss, node->children[i]); plb << eval_token(ss, node->children[i]);
plb << retval; plb << retval;
try { try {
retval = dispatch(ss.get_function(node->children[i+1]->text), plb); retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
} }
catch(const dispatchkit::dispatch_error &){ catch(const dispatch_error &){
throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]); throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]);
} }
} }
@@ -165,8 +170,13 @@ namespace chaiscript
* Evaluates a variable declaration * Evaluates a variable declaration
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) { Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) {
ss.add_object(node->children[0]->text, dispatchkit::Boxed_Value()); try {
ss.add_object(node->children[0]->text, Boxed_Value());
}
catch (reserved_word_error &rwe) {
throw Eval_Error("Reserved word used as variable '" + node->children[0]->text + "'", node);
}
return ss.get_object(node->children[0]->text); return ss.get_object(node->children[0]->text);
} }
@@ -174,8 +184,8 @@ namespace chaiscript
* Evaluates binary boolean operators. Respects short-circuiting rules. * Evaluates binary boolean operators. Respects short-circuiting rules.
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_expression(Eval_System &ss, TokenPtr node) { Boxed_Value eval_expression(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
@@ -183,9 +193,9 @@ namespace chaiscript
for (i = 1; i < node->children.size(); i += 2) { for (i = 1; i < node->children.size(); i += 2) {
bool lhs; bool lhs;
try { try {
lhs = dispatchkit::boxed_cast<bool &>(retval); lhs = boxed_cast<bool &>(retval);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
throw Eval_Error("Condition not boolean", node); throw Eval_Error("Condition not boolean", node);
} }
if (node->children[i]->text == "&&") { if (node->children[i]->text == "&&") {
@@ -193,12 +203,12 @@ namespace chaiscript
retval = eval_token(ss, node->children[i+1]); retval = eval_token(ss, node->children[i+1]);
} }
else { else {
retval = dispatchkit::Boxed_Value(false); retval = Boxed_Value(false);
} }
} }
else if (node->children[i]->text == "||") { else if (node->children[i]->text == "||") {
if (lhs) { if (lhs) {
retval = dispatchkit::Boxed_Value(true); retval = Boxed_Value(true);
} }
else { else {
retval = eval_token(ss, node->children[i+1]); retval = eval_token(ss, node->children[i+1]);
@@ -213,21 +223,21 @@ namespace chaiscript
* Evaluates comparison, additions, and multiplications and their relatives * Evaluates comparison, additions, and multiplications and their relatives
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_comp_add_mul(Eval_System &ss, TokenPtr node) { Boxed_Value eval_comp_add_mul(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
if (node->children.size() > 1) { if (node->children.size() > 1) {
for (i = 1; i < node->children.size(); i += 2) { for (i = 1; i < node->children.size(); i += 2) {
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << retval; plb << retval;
plb << eval_token(ss, node->children[i + 1]); plb << eval_token(ss, node->children[i + 1]);
try { try {
retval = dispatch(ss.get_function(node->children[i]->text), plb); retval = dispatch(ss.get_function(node->children[i]->text), plb);
} }
catch(const dispatchkit::dispatch_error &){ catch(const dispatch_error &){
throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]); throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]);
} }
} }
@@ -240,13 +250,13 @@ namespace chaiscript
* Evaluates an array lookup * Evaluates an array lookup
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_array_call(Eval_System &ss, TokenPtr node) { Boxed_Value eval_array_call(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
for (i = 1; i < node->children.size(); ++i) { for (i = 1; i < node->children.size(); ++i) {
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << retval; plb << retval;
plb << eval_token(ss, node->children[i]); plb << eval_token(ss, node->children[i]);
try { try {
@@ -255,7 +265,7 @@ namespace chaiscript
catch(std::out_of_range &) { catch(std::out_of_range &) {
throw Eval_Error("Out of bounds exception", node); throw Eval_Error("Out of bounds exception", node);
} }
catch(const dispatchkit::dispatch_error &){ catch(const dispatch_error &){
throw Eval_Error("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]); throw Eval_Error("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]);
} }
} }
@@ -267,13 +277,13 @@ namespace chaiscript
* Evaluates a unary negation * Evaluates a unary negation
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_negate(Eval_System &ss, TokenPtr node) { Boxed_Value eval_negate(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << retval; plb << retval;
plb << dispatchkit::Boxed_Value(-1.0); plb << Boxed_Value(-1.0);
try { try {
return dispatch(ss.get_function("*"), plb); return dispatch(ss.get_function("*"), plb);
@@ -287,29 +297,29 @@ namespace chaiscript
* Evaluates a unary boolean not * Evaluates a unary boolean not
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_not(Eval_System &ss, TokenPtr node) { Boxed_Value eval_not(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
bool cond; bool cond;
try { try {
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
cond = dispatchkit::boxed_cast<bool &>(retval); cond = boxed_cast<bool &>(retval);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]); throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]);
} }
return dispatchkit::Boxed_Value(!cond); return Boxed_Value(!cond);
} }
/** /**
* Evaluates any unary prefix * Evaluates any unary prefix
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_prefix(Eval_System &ss, TokenPtr node) { Boxed_Value eval_prefix(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
retval = eval_token(ss, node->children[1]); retval = eval_token(ss, node->children[1]);
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << retval; plb << retval;
try { try {
@@ -324,25 +334,25 @@ namespace chaiscript
* Evaluates (and generates) an inline array initialization * Evaluates (and generates) an inline array initialization
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_inline_array(Eval_System &ss, TokenPtr node) { Boxed_Value eval_inline_array(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
try { try {
retval = dispatch(ss.get_function("Vector"), dispatchkit::Param_List_Builder()); retval = dispatch(ss.get_function("Vector"), Param_List_Builder());
if (node->children.size() > 0) { if (node->children.size() > 0) {
for (i = 0; i < node->children[0]->children.size(); ++i) { for (i = 0; i < node->children[0]->children.size(); ++i) {
try { try {
dispatchkit::Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]); Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]);
dispatch(ss.get_function("push_back"), dispatchkit::Param_List_Builder() << retval << tmp); dispatch(ss.get_function("push_back"), Param_List_Builder() << retval << tmp);
} }
catch (const dispatchkit::dispatch_error &) { catch (const dispatch_error &) {
throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]); throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]);
} }
} }
} }
} }
catch (const dispatchkit::dispatch_error &) { catch (const dispatch_error &) {
throw Eval_Error("Can not find appropriate 'Vector()'", node); throw Eval_Error("Can not find appropriate 'Vector()'", node);
} }
@@ -353,13 +363,13 @@ namespace chaiscript
* Evaluates (and generates) an inline range initialization * Evaluates (and generates) an inline range initialization
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_inline_range(Eval_System &ss, TokenPtr node) { Boxed_Value eval_inline_range(Eval_System &ss, TokenPtr node) {
try { try {
return dispatch(ss.get_function("generate_range"), dispatchkit::Param_List_Builder() return dispatch(ss.get_function("generate_range"), Param_List_Builder()
<< eval_token(ss, node->children[0]->children[0]->children[0]) << eval_token(ss, node->children[0]->children[0]->children[0])
<< eval_token(ss, node->children[0]->children[0]->children[1])); << eval_token(ss, node->children[0]->children[0]->children[1]));
} }
catch (const dispatchkit::dispatch_error &) { catch (const dispatch_error &) {
throw Eval_Error("Unable to generate range vector", node); throw Eval_Error("Unable to generate range vector", node);
} }
} }
@@ -368,24 +378,24 @@ namespace chaiscript
* Evaluates (and generates) an inline map initialization * Evaluates (and generates) an inline map initialization
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_inline_map(Eval_System &ss, TokenPtr node) { Boxed_Value eval_inline_map(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
try { try {
retval = dispatch(ss.get_function("Map"), dispatchkit::Param_List_Builder()); retval = dispatch(ss.get_function("Map"), Param_List_Builder());
for (i = 0; i < node->children[0]->children.size(); ++i) { for (i = 0; i < node->children[0]->children.size(); ++i) {
try { try {
dispatchkit::Boxed_Value key = eval_token(ss, node->children[0]->children[i]->children[0]); Boxed_Value key = eval_token(ss, node->children[0]->children[i]->children[0]);
dispatchkit::Boxed_Value slot = dispatch(ss.get_function("[]"), dispatchkit::Param_List_Builder() << retval << key); Boxed_Value slot = dispatch(ss.get_function("[]"), Param_List_Builder() << retval << key);
dispatch(ss.get_function("="), dispatchkit::Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1])); dispatch(ss.get_function("="), Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1]));
} }
catch (const dispatchkit::dispatch_error &) { catch (const dispatch_error &) {
throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]); throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]);
} }
} }
} }
catch (const dispatchkit::dispatch_error &) { catch (const dispatch_error &) {
throw Eval_Error("Can not find appropriate 'Map()'", node); throw Eval_Error("Can not find appropriate 'Map()'", node);
} }
@@ -396,21 +406,21 @@ namespace chaiscript
* Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call. * Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call.
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_fun_call(Eval_System &ss, TokenPtr node) { Boxed_Value eval_fun_call(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack prev_stack = ss.get_stack();
dispatchkit::Dispatch_Engine::Stack new_stack; Dispatch_Engine::Stack new_stack = ss.new_stack();
unsigned int i; unsigned int i;
new_stack.push_back(dispatchkit::Dispatch_Engine::Scope()); new_stack->push_back(Dispatch_Engine::Scope());
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) { if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
for (i = 0; i < node->children[1]->children.size(); ++i) { for (i = 0; i < node->children[1]->children.size(); ++i) {
plb << eval_token(ss, node->children[1]->children[i]); plb << eval_token(ss, node->children[1]->children[i]);
} }
} }
dispatchkit::Boxed_Value fn; Boxed_Value fn;
try { try {
fn = eval_token(ss, node->children[0]); fn = eval_token(ss, node->children[0]);
} }
@@ -420,10 +430,10 @@ namespace chaiscript
} }
try { try {
ss.set_stack(new_stack); ss.set_stack(new_stack);
retval = (*dispatchkit::boxed_cast<boost::shared_ptr<dispatchkit::Proxy_Function> >(fn))(plb); retval = (*boxed_cast<Proxy_Function >(fn))(plb);
ss.set_stack(prev_stack); ss.set_stack(prev_stack);
} }
catch(const dispatchkit::dispatch_error &e){ catch(const dispatch_error &e){
ss.set_stack(prev_stack); ss.set_stack(prev_stack);
throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]);
} }
@@ -443,21 +453,21 @@ namespace chaiscript
* Evaluates a method/attributes invocation * Evaluates a method/attributes invocation
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_dot_access(Eval_System &ss, TokenPtr node) { Boxed_Value eval_dot_access(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
std::vector<std::pair<std::string, boost::shared_ptr<dispatchkit::Proxy_Function> > > fn; std::vector<std::pair<std::string, Proxy_Function > > fn;
dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack prev_stack = ss.get_stack();
dispatchkit::Dispatch_Engine::Stack new_stack; Dispatch_Engine::Stack new_stack = ss.new_stack();
unsigned int i, j; unsigned int i, j;
new_stack.push_back(dispatchkit::Dispatch_Engine::Scope()); new_stack->push_back(Dispatch_Engine::Scope());
//todo: Please extract a single way of doing function calls between this and eval_fun_call //todo: Please extract a single way of doing function calls between this and eval_fun_call
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
if (node->children.size() > 1) { if (node->children.size() > 1) {
for (i = 1; i < node->children.size(); ++i) { for (i = 1; i < node->children.size(); ++i) {
dispatchkit::Param_List_Builder plb; Param_List_Builder plb;
plb << retval; plb << retval;
if (node->children[i]->children.size() > 1) { if (node->children[i]->children.size() > 1) {
@@ -466,23 +476,32 @@ namespace chaiscript
} }
} }
std::string fun_name; //std::string fun_name;
Boxed_Value fn;
try {
if (node->children[i]->identifier == Token_Type::Fun_Call) { if (node->children[i]->identifier == Token_Type::Fun_Call) {
fun_name = node->children[i]->children[0]->text; //fun_name = node->children[i]->children[0]->text;
fn = eval_token(ss, node->children[i]->children[0]);
} }
else { else {
fun_name = node->children[i]->text; //fun_name = node->children[i]->text;
fn = eval_token(ss, node->children[i]);
}
}
catch(Eval_Error &ee) {
ss.set_stack(prev_stack);
throw Eval_Error(ee.reason, node->children[i]);
} }
try { try {
fn = ss.get_function(fun_name); //fn = ss.get_function(fun_name);
ss.set_stack(new_stack); ss.set_stack(new_stack);
retval = dispatch(fn, plb); //retval = dispatch(fn, plb);
retval = (*boxed_cast<Proxy_Function >(fn))(plb);
ss.set_stack(prev_stack); ss.set_stack(prev_stack);
} }
catch(const dispatchkit::dispatch_error &e){ catch(const dispatch_error &e){
ss.set_stack(prev_stack); ss.set_stack(prev_stack);
throw Eval_Error(std::string(e.what()) + " with function '" + fun_name + "'", node->children[i]); throw Eval_Error(std::string(e.what()), node->children[i]);
} }
catch(Return_Value &rv) { catch(Return_Value &rv) {
ss.set_stack(prev_stack); ss.set_stack(prev_stack);
@@ -502,16 +521,16 @@ namespace chaiscript
* Evaluates an if/elseif/else block * Evaluates an if/elseif/else block
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_if(Eval_System &ss, TokenPtr node) { Boxed_Value eval_if(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
bool cond; bool cond;
try { try {
cond = dispatchkit::boxed_cast<bool &>(retval); cond = boxed_cast<bool &>(retval);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
throw Eval_Error("If condition not boolean", node->children[0]); throw Eval_Error("If condition not boolean", node->children[0]);
} }
if (cond) { if (cond) {
@@ -525,13 +544,13 @@ namespace chaiscript
retval = eval_token(ss, node->children[i+1]); retval = eval_token(ss, node->children[i+1]);
cond = true; cond = true;
} }
else if (node->children[i]->text == "elseif") { else if (node->children[i]->text == "else if") {
retval = eval_token(ss, node->children[i+1]); retval = eval_token(ss, node->children[i+1]);
try { try {
cond = dispatchkit::boxed_cast<bool &>(retval); cond = boxed_cast<bool &>(retval);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
throw Eval_Error("Elseif condition not boolean", node->children[i+1]); throw Eval_Error("'else if' condition not boolean", node->children[i+1]);
} }
if (cond) { if (cond) {
retval = eval_token(ss, node->children[i+2]); retval = eval_token(ss, node->children[i+2]);
@@ -549,25 +568,26 @@ namespace chaiscript
* Evaluates a while block * Evaluates a while block
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_while(Eval_System &ss, TokenPtr node) { Boxed_Value eval_while(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval;
retval = eval_token(ss, node->children[0]);
bool cond; bool cond;
ss.new_scope();
try { try {
cond = dispatchkit::boxed_cast<bool &>(retval); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("While condition not boolean", node->children[0]); throw Eval_Error("While condition not boolean", node->children[0]);
} }
while (cond) { while (cond) {
try { try {
eval_token(ss, node->children[1]); eval_token(ss, node->children[1]);
retval = eval_token(ss, node->children[0]);
try { try {
cond = dispatchkit::boxed_cast<bool &>(retval); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("While condition not boolean", node->children[0]); throw Eval_Error("While condition not boolean", node->children[0]);
} }
} }
@@ -575,30 +595,30 @@ namespace chaiscript
cond = false; cond = false;
} }
} }
return dispatchkit::Boxed_Value(); ss.pop_scope();
return Boxed_Value();
} }
/** /**
* Evaluates a for block, including the for's conditions, from left to right * Evaluates a for block, including the for's conditions, from left to right
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_for(Eval_System &ss, TokenPtr node) { Boxed_Value eval_for(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval;
dispatchkit::Boxed_Value condition;
bool cond; bool cond;
ss.new_scope();
try { try {
if (node->children.size() == 4) { if (node->children.size() == 4) {
eval_token(ss, node->children[0]); eval_token(ss, node->children[0]);
condition = eval_token(ss, node->children[1]); cond = boxed_cast<bool &>(eval_token(ss, node->children[1]));
} }
else if (node->children.size() == 3){ else {
condition = eval_token(ss, node->children[0]); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
cond = dispatchkit::boxed_cast<bool &>(condition);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("For condition not boolean", node); throw Eval_Error("For condition not boolean", node);
} }
while (cond) { while (cond) {
@@ -606,37 +626,37 @@ namespace chaiscript
if (node->children.size() == 4) { if (node->children.size() == 4) {
eval_token(ss, node->children[3]); eval_token(ss, node->children[3]);
eval_token(ss, node->children[2]); eval_token(ss, node->children[2]);
condition = eval_token(ss, node->children[1]); cond = boxed_cast<bool &>(eval_token(ss, node->children[1]));
} }
else if (node->children.size() == 3) { else {
eval_token(ss, node->children[2]); eval_token(ss, node->children[2]);
eval_token(ss, node->children[1]); eval_token(ss, node->children[1]);
condition = eval_token(ss, node->children[0]); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
cond = dispatchkit::boxed_cast<bool &>(condition);
} }
catch (const dispatchkit::bad_boxed_cast &) { catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("For condition not boolean", node); throw Eval_Error("For condition not boolean", node);
} }
catch (Break_Loop &) { catch (Break_Loop &) {
cond = false; cond = false;
} }
} }
return dispatchkit::Boxed_Value(); ss.pop_scope();
return Boxed_Value();
} }
/** /**
* Evaluates a function definition * Evaluates a function definition
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_def(Eval_System &ss, TokenPtr node) { Boxed_Value eval_def(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
std::vector<std::string> param_names; std::vector<std::string> param_names;
std::string annotation = node->annotation?node->annotation->text:""; std::string annotation = node->annotation?node->annotation->text:"";
boost::shared_ptr<dispatchkit::Dynamic_Proxy_Function> guard; boost::shared_ptr<Dynamic_Proxy_Function> guard;
size_t numparams = 0; size_t numparams = 0;
std::string function_name = node->children[0]->text; std::string function_name = node->children[0]->text;
TokenPtr guardnode; TokenPtr guardnode;
@@ -661,18 +681,22 @@ namespace chaiscript
} }
if (guardnode) { if (guardnode) {
guard = boost::shared_ptr<dispatchkit::Dynamic_Proxy_Function> guard = boost::shared_ptr<Dynamic_Proxy_Function>
(new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>, (new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
boost::ref(ss), guardnode, boost::ref(ss), guardnode,
param_names, _1), numparams)); param_names, _1), numparams));
} }
ss.register_function(boost::shared_ptr<dispatchkit::Proxy_Function> try {
(new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>, ss.add(Proxy_Function
(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
boost::ref(ss), node->children.back(), boost::ref(ss), node->children.back(),
param_names, _1), numparams, param_names, _1), numparams,
annotation, guard)), function_name); annotation, guard)), function_name);
}
catch (reserved_word_error &rwe) {
throw Eval_Error("Reserved word used as function name '" + function_name + "'", node);
}
return retval; return retval;
} }
@@ -680,8 +704,8 @@ namespace chaiscript
* Evaluates a lambda (anonymous function) * Evaluates a lambda (anonymous function)
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_lambda(Eval_System &ss, TokenPtr node) { Boxed_Value eval_lambda(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
std::vector<std::string> param_names; std::vector<std::string> param_names;
@@ -699,8 +723,8 @@ namespace chaiscript
numparams = 0; numparams = 0;
} }
return dispatchkit::Boxed_Value(boost::shared_ptr<dispatchkit::Proxy_Function>( return Boxed_Value(Proxy_Function(
new dispatchkit::Dynamic_Proxy_Function( new Dynamic_Proxy_Function(
boost::bind(&eval_function<Eval_System>, boost::ref(ss), node->children.back(), param_names, _1), numparams))); boost::bind(&eval_function<Eval_System>, boost::ref(ss), node->children.back(), param_names, _1), numparams)));
} }
@@ -708,8 +732,8 @@ namespace chaiscript
* Evaluates a scoped block. Handles resetting the scope after the block has completed. * Evaluates a scoped block. Handles resetting the scope after the block has completed.
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_block(Eval_System &ss, TokenPtr node) { Boxed_Value eval_block(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
unsigned int i; unsigned int i;
ss.new_scope(); ss.new_scope();
@@ -736,13 +760,13 @@ namespace chaiscript
* Evaluates a return statement * Evaluates a return statement
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_return(Eval_System &ss, TokenPtr node) { Boxed_Value eval_return(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval; Boxed_Value retval;
if (node->children.size() > 0) { if (node->children.size() > 0) {
retval = eval_token(ss, node->children[0]); retval = eval_token(ss, node->children[0]);
} }
else { else {
retval = dispatchkit::Boxed_Value(); retval = Boxed_Value();
} }
throw Return_Value(retval, node); throw Return_Value(retval, node);
} }
@@ -751,7 +775,7 @@ namespace chaiscript
* Evaluates a break statement * Evaluates a break statement
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_break(Eval_System &, TokenPtr node) { Boxed_Value eval_break(Eval_System &, TokenPtr node) {
throw Break_Loop(node); throw Break_Loop(node);
} }
@@ -759,122 +783,121 @@ namespace chaiscript
* Top-level evaluation dispatch for all AST node types * Top-level evaluation dispatch for all AST node types
*/ */
template <typename Eval_System> template <typename Eval_System>
dispatchkit::Boxed_Value eval_token(Eval_System &ss, TokenPtr node) { Boxed_Value eval_token(Eval_System &ss, TokenPtr node) {
dispatchkit::Boxed_Value retval;
switch (node->identifier) { switch (node->identifier) {
case (Token_Type::File) : case (Token_Type::File) :
retval = eval_file(ss, node); return eval_file(ss, node);
break; break;
case (Token_Type::Id) : case (Token_Type::Id) :
retval = eval_id(ss, node); return eval_id(ss, node);
break; break;
case (Token_Type::Float) : case (Token_Type::Float) :
retval = eval_float(ss, node); return eval_float(ss, node);
break; break;
case (Token_Type::Int) : case (Token_Type::Int) :
retval = eval_int(ss, node); return eval_int(ss, node);
break; break;
case (Token_Type::Quoted_String) : case (Token_Type::Quoted_String) :
retval = eval_quoted_string(ss, node); return eval_quoted_string(ss, node);
break; break;
case (Token_Type::Single_Quoted_String) : case (Token_Type::Single_Quoted_String) :
retval = eval_single_quoted_string(ss, node); return eval_single_quoted_string(ss, node);
break; break;
case (Token_Type::Equation) : case (Token_Type::Equation) :
retval = eval_equation(ss, node); return eval_equation(ss, node);
break; break;
case (Token_Type::Var_Decl) : case (Token_Type::Var_Decl) :
retval = eval_var_decl(ss, node); return eval_var_decl(ss, node);
break; break;
case (Token_Type::Expression) : case (Token_Type::Expression) :
retval = eval_expression(ss, node); return eval_expression(ss, node);
break; break;
case (Token_Type::Comparison) : case (Token_Type::Comparison) :
case (Token_Type::Additive) : case (Token_Type::Additive) :
case (Token_Type::Multiplicative) : case (Token_Type::Multiplicative) :
retval = eval_comp_add_mul(ss, node); return eval_comp_add_mul(ss, node);
break; break;
case (Token_Type::Array_Call) : case (Token_Type::Array_Call) :
retval = eval_array_call(ss, node); return eval_array_call(ss, node);
break; break;
case (Token_Type::Negate) : case (Token_Type::Negate) :
retval = eval_negate(ss, node); return eval_negate(ss, node);
break; break;
case (Token_Type::Not) : case (Token_Type::Not) :
retval = eval_not(ss, node); return eval_not(ss, node);
break; break;
case (Token_Type::Prefix) : case (Token_Type::Prefix) :
retval = eval_prefix(ss, node); return eval_prefix(ss, node);
break; break;
case (Token_Type::Inline_Array) : case (Token_Type::Inline_Array) :
retval = eval_inline_array(ss, node); return eval_inline_array(ss, node);
break; break;
case (Token_Type::Inline_Range) : case (Token_Type::Inline_Range) :
retval = eval_inline_range(ss, node); return eval_inline_range(ss, node);
break; break;
case (Token_Type::Inline_Map) : case (Token_Type::Inline_Map) :
retval = eval_inline_map(ss, node); return eval_inline_map(ss, node);
break; break;
case (Token_Type::Fun_Call) : case (Token_Type::Fun_Call) :
retval = eval_fun_call(ss, node); return eval_fun_call(ss, node);
break; break;
case (Token_Type::Dot_Access) : case (Token_Type::Dot_Access) :
retval = eval_dot_access(ss, node); return eval_dot_access(ss, node);
break; break;
case(Token_Type::If) : case(Token_Type::If) :
retval = eval_if(ss, node); return eval_if(ss, node);
break; break;
case(Token_Type::While) : case(Token_Type::While) :
retval = eval_while(ss, node); return eval_while(ss, node);
break; break;
case(Token_Type::For) : case(Token_Type::For) :
retval = eval_for(ss, node); return eval_for(ss, node);
break; break;
case (Token_Type::Def) : case (Token_Type::Def) :
retval = eval_def(ss, node); return eval_def(ss, node);
break; break;
case (Token_Type::Lambda) : case (Token_Type::Lambda) :
retval = eval_lambda(ss, node); return eval_lambda(ss, node);
break; break;
case (Token_Type::Block) : case (Token_Type::Block) :
retval = eval_block(ss, node); return eval_block(ss, node);
break; break;
case (Token_Type::Return) : case (Token_Type::Return) :
retval = eval_return(ss, node); return eval_return(ss, node);
break; break;
case (Token_Type::Break) : case (Token_Type::Break) :
retval = eval_break(ss, node); return eval_break(ss, node);
break; break;
}
return retval; default :
return Boxed_Value();
}
} }
} }
#endif /* CHAISCRIPT_EVAL_HPP_ */ #endif /* CHAISCRIPT_EVAL_HPP_ */

View File

@@ -140,7 +140,7 @@ namespace chaiscript
*/ */
bool Float_() { bool Float_() {
bool retval = false; bool retval = false;
if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*input_pos == '.'))) {
while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) {
++input_pos; ++input_pos;
++col; ++col;
@@ -178,7 +178,7 @@ namespace chaiscript
std::string::iterator start = input_pos; std::string::iterator start = input_pos;
int prev_col = col; int prev_col = col;
int prev_line = line; int prev_line = line;
if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) { if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*input_pos == '.')) ) {
if (Float_()) { if (Float_()) {
std::string match(start, input_pos); std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col)); TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col));
@@ -301,7 +301,7 @@ namespace chaiscript
++col; ++col;
} }
else { else {
throw Parse_Error("Unclosed quoted string", File_Position(line, col), filename); throw Eval_Error("Unclosed quoted string", File_Position(line, col), filename);
} }
} }
return retval; return retval;
@@ -343,7 +343,7 @@ namespace chaiscript
case ('t') : match.push_back('\t'); break; case ('t') : match.push_back('\t'); break;
case ('\'') : match.push_back('\''); break; case ('\'') : match.push_back('\''); break;
case ('\"') : match.push_back('\"'); break; case ('\"') : match.push_back('\"'); break;
default: throw Parse_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename);
} }
} }
else { else {
@@ -392,7 +392,7 @@ namespace chaiscript
++col; ++col;
} }
else { else {
throw Parse_Error("Unclosed single-quoted string", File_Position(line, col), filename); throw Eval_Error("Unclosed single-quoted string", File_Position(line, col), filename);
} }
} }
return retval; return retval;
@@ -434,7 +434,7 @@ namespace chaiscript
case ('t') : match.push_back('\t'); break; case ('t') : match.push_back('\t'); break;
case ('\'') : match.push_back('\''); break; case ('\'') : match.push_back('\''); break;
case ('\"') : match.push_back('\"'); break; case ('\"') : match.push_back('\"'); break;
default: throw Parse_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename); default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename);
} }
} }
else { else {
@@ -694,7 +694,7 @@ namespace chaiscript
if (Char(',')) { if (Char(',')) {
do { do {
if (!Equation()) { if (!Equation()) {
throw Parse_Error("Unexpected value in parameter list", match_stack.back()); throw Eval_Error("Unexpected value in parameter list", match_stack.back());
} }
} while (retval && Char(',')); } while (retval && Char(','));
} }
@@ -721,7 +721,7 @@ namespace chaiscript
if (Char(',')) { if (Char(',')) {
do { do {
if (!Map_Pair()) { if (!Map_Pair()) {
throw Parse_Error("Unexpected value in container", match_stack.back()); throw Eval_Error("Unexpected value in container", match_stack.back());
} }
} while (retval && Char(',')); } while (retval && Char(','));
} }
@@ -746,14 +746,14 @@ namespace chaiscript
if (Char('(')) { if (Char('(')) {
Arg_List(); Arg_List();
if (!Char(')')) { if (!Char(')')) {
throw Parse_Error("Incomplete anonymous function", File_Position(line, col), filename); throw Eval_Error("Incomplete anonymous function", File_Position(line, col), filename);
} }
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete anonymous function", File_Position(line, col), filename); throw Eval_Error("Incomplete anonymous function", File_Position(line, col), filename);
} }
build_match(Token_Type::Lambda, prev_stack_top); build_match(Token_Type::Lambda, prev_stack_top);
@@ -784,13 +784,13 @@ namespace chaiscript
retval = true; retval = true;
if (!Id(true)) { if (!Id(true)) {
throw Parse_Error("Missing function name in definition", File_Position(line, col), filename); throw Eval_Error("Missing function name in definition", File_Position(line, col), filename);
} }
if (Char('(')) { if (Char('(')) {
Arg_List(); Arg_List();
if (!Char(')')) { if (!Char(')')) {
throw Parse_Error("Incomplete function definition", File_Position(line, col), filename); throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
} }
} }
@@ -798,13 +798,13 @@ namespace chaiscript
if (Char(':')) { if (Char(':')) {
if (!Expression()) { if (!Expression()) {
throw Parse_Error("Missing guard expression for function", File_Position(line, col), filename); throw Eval_Error("Missing guard expression for function", File_Position(line, col), filename);
} }
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete function definition", File_Position(line, col), filename); throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
} }
build_match(Token_Type::Def, prev_stack_top); build_match(Token_Type::Def, prev_stack_top);
@@ -829,48 +829,51 @@ namespace chaiscript
retval = true; retval = true;
if (!Char('(')) { if (!Char('(')) {
throw Parse_Error("Incomplete 'if' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'if' expression", File_Position(line, col), filename);
} }
if (!(Expression() && Char(')'))) { if (!(Expression() && Char(')'))) {
throw Parse_Error("Incomplete 'if' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'if' expression", File_Position(line, col), filename);
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete 'if' block", File_Position(line, col), filename); throw Eval_Error("Incomplete 'if' block", File_Position(line, col), filename);
} }
bool has_matches = true; bool has_matches = true;
while (has_matches) { while (has_matches) {
while (Eol()); while (Eol());
has_matches = false; has_matches = false;
if (Keyword("elseif", true)) { if (Keyword("else", true)) {
if (Keyword("if")) {
match_stack.back()->text = "else if";
if (!Char('(')) { if (!Char('(')) {
throw Parse_Error("Incomplete 'elseif' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'else if' expression", File_Position(line, col), filename);
} }
if (!(Expression() && Char(')'))) { if (!(Expression() && Char(')'))) {
throw Parse_Error("Incomplete 'elseif' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'else if' expression", File_Position(line, col), filename);
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete 'elseif' block", File_Position(line, col), filename); throw Eval_Error("Incomplete 'else if' block", File_Position(line, col), filename);
} }
has_matches = true; has_matches = true;
} }
else if (Keyword("else", true)) { else {
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete 'else' block", File_Position(line, col), filename); throw Eval_Error("Incomplete 'else' block", File_Position(line, col), filename);
} }
has_matches = true; has_matches = true;
} }
} }
}
build_match(Token_Type::If, prev_stack_top); build_match(Token_Type::If, prev_stack_top);
} }
@@ -890,17 +893,17 @@ namespace chaiscript
retval = true; retval = true;
if (!Char('(')) { if (!Char('(')) {
throw Parse_Error("Incomplete 'while' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'while' expression", File_Position(line, col), filename);
} }
if (!(Expression() && Char(')'))) { if (!(Expression() && Char(')'))) {
throw Parse_Error("Incomplete 'while' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'while' expression", File_Position(line, col), filename);
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete 'while' block", File_Position(line, col), filename); throw Eval_Error("Incomplete 'while' block", File_Position(line, col), filename);
} }
build_match(Token_Type::While, prev_stack_top); build_match(Token_Type::While, prev_stack_top);
@@ -919,7 +922,7 @@ namespace chaiscript
return true; return true;
} }
else { else {
throw Parse_Error("Incomplete conditions in 'for' loop", File_Position(line, col), filename); throw Eval_Error("Incomplete conditions in 'for' loop", File_Position(line, col), filename);
} }
} }
@@ -935,17 +938,17 @@ namespace chaiscript
retval = true; retval = true;
if (!Char('(')) { if (!Char('(')) {
throw Parse_Error("Incomplete 'for' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'for' expression", File_Position(line, col), filename);
} }
if (!(For_Guards() && Char(')'))) { if (!(For_Guards() && Char(')'))) {
throw Parse_Error("Incomplete 'for' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete 'for' expression", File_Position(line, col), filename);
} }
while (Eol()); while (Eol());
if (!Block()) { if (!Block()) {
throw Parse_Error("Incomplete 'for' block", File_Position(line, col), filename); throw Eval_Error("Incomplete 'for' block", File_Position(line, col), filename);
} }
build_match(Token_Type::For, prev_stack_top); build_match(Token_Type::For, prev_stack_top);
@@ -967,7 +970,7 @@ namespace chaiscript
Statements(); Statements();
if (!Char('}')) { if (!Char('}')) {
throw Parse_Error("Incomplete block", File_Position(line, col), filename); throw Eval_Error("Incomplete block", File_Position(line, col), filename);
} }
build_match(Token_Type::Block, prev_stack_top); build_match(Token_Type::Block, prev_stack_top);
@@ -1031,7 +1034,7 @@ namespace chaiscript
Arg_List(); Arg_List();
if (!Char(')')) { if (!Char(')')) {
throw Parse_Error("Incomplete function call", File_Position(line, col), filename); throw Eval_Error("Incomplete function call", File_Position(line, col), filename);
} }
build_match(Token_Type::Fun_Call, prev_stack_top); build_match(Token_Type::Fun_Call, prev_stack_top);
@@ -1040,7 +1043,7 @@ namespace chaiscript
has_more = true; has_more = true;
if (!(Expression() && Char(']'))) { if (!(Expression() && Char(']'))) {
throw Parse_Error("Incomplete array access", File_Position(line, col), filename); throw Eval_Error("Incomplete array access", File_Position(line, col), filename);
} }
build_match(Token_Type::Array_Call, prev_stack_top); build_match(Token_Type::Array_Call, prev_stack_top);
@@ -1063,7 +1066,7 @@ namespace chaiscript
retval = true; retval = true;
if (!Id(true)) { if (!Id(true)) {
throw Parse_Error("Incomplete variable declaration", File_Position(line, col), filename); throw Eval_Error("Incomplete variable declaration", File_Position(line, col), filename);
} }
build_match(Token_Type::Var_Decl, prev_stack_top); build_match(Token_Type::Var_Decl, prev_stack_top);
@@ -1081,10 +1084,10 @@ namespace chaiscript
if (Char('(')) { if (Char('(')) {
retval = true; retval = true;
if (!Expression()) { if (!Expression()) {
throw Parse_Error("Incomplete expression", File_Position(line, col), filename); throw Eval_Error("Incomplete expression", File_Position(line, col), filename);
} }
if (!Char(')')) { if (!Char(')')) {
throw Parse_Error("Missing closing parenthesis", File_Position(line, col), filename); throw Eval_Error("Missing closing parenthesis", File_Position(line, col), filename);
} }
} }
return retval; return retval;
@@ -1102,7 +1105,7 @@ namespace chaiscript
retval = true; retval = true;
Container_Arg_List(); Container_Arg_List();
if (!Char(']')) { if (!Char(']')) {
throw Parse_Error("Missing closing square bracket", File_Position(line, col), filename); throw Eval_Error("Missing closing square bracket", File_Position(line, col), filename);
} }
if ((prev_stack_top != match_stack.size()) && (match_stack.back()->children.size() > 0)) { if ((prev_stack_top != match_stack.size()) && (match_stack.back()->children.size() > 0)) {
if (match_stack.back()->children[0]->identifier == Token_Type::Value_Range) { if (match_stack.back()->children[0]->identifier == Token_Type::Value_Range) {
@@ -1144,7 +1147,7 @@ namespace chaiscript
while ((input_pos != input_end) && (*input_pos != '`')) { while ((input_pos != input_end) && (*input_pos != '`')) {
if (Eol()) { if (Eol()) {
throw Parse_Error("Carriage return in identifier literal", File_Position(line, col), filename); throw Eval_Error("Carriage return in identifier literal", File_Position(line, col), filename);
} }
else { else {
++input_pos; ++input_pos;
@@ -1153,10 +1156,10 @@ namespace chaiscript
} }
if (start == input_pos) { if (start == input_pos) {
throw Parse_Error("Missing contents of identifier literal", File_Position(line, col), filename); throw Eval_Error("Missing contents of identifier literal", File_Position(line, col), filename);
} }
else if (input_pos == input_end) { else if (input_pos == input_end) {
throw Parse_Error("Incomplete identifier literal", File_Position(line, col), filename); throw Eval_Error("Incomplete identifier literal", File_Position(line, col), filename);
} }
++col; ++col;
@@ -1182,7 +1185,7 @@ namespace chaiscript
retval = true; retval = true;
if (!Dot_Access()) { if (!Dot_Access()) {
throw Parse_Error("Incomplete negation expression", File_Position(line, col), filename); throw Eval_Error("Incomplete negation expression", File_Position(line, col), filename);
} }
build_match(Token_Type::Negate, prev_stack_top); build_match(Token_Type::Negate, prev_stack_top);
@@ -1191,7 +1194,7 @@ namespace chaiscript
retval = true; retval = true;
if (!Dot_Access()) { if (!Dot_Access()) {
throw Parse_Error("Incomplete '!' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete '!' expression", File_Position(line, col), filename);
} }
build_match(Token_Type::Not, prev_stack_top); build_match(Token_Type::Not, prev_stack_top);
@@ -1200,7 +1203,7 @@ namespace chaiscript
retval = true; retval = true;
if (!Dot_Access()) { if (!Dot_Access()) {
throw Parse_Error("Incomplete '++' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete '++' expression", File_Position(line, col), filename);
} }
build_match(Token_Type::Prefix, prev_stack_top); build_match(Token_Type::Prefix, prev_stack_top);
@@ -1209,7 +1212,7 @@ namespace chaiscript
retval = true; retval = true;
if (!Dot_Access()) { if (!Dot_Access()) {
throw Parse_Error("Incomplete '--' expression", File_Position(line, col), filename); throw Eval_Error("Incomplete '--' expression", File_Position(line, col), filename);
} }
build_match(Token_Type::Prefix, prev_stack_top); build_match(Token_Type::Prefix, prev_stack_top);
@@ -1244,7 +1247,7 @@ namespace chaiscript
if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) { if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) {
do { do {
if (!Additive()) { if (!Additive()) {
throw Parse_Error("Incomplete comparison expression", File_Position(line, col), filename); throw Eval_Error("Incomplete comparison expression", File_Position(line, col), filename);
} }
} while (retval && (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true))); } while (retval && (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)));
@@ -1268,7 +1271,7 @@ namespace chaiscript
if (Symbol("+", true) || Symbol("-", true)) { if (Symbol("+", true) || Symbol("-", true)) {
do { do {
if (!Multiplicative()) { if (!Multiplicative()) {
throw Parse_Error("Incomplete math expression", File_Position(line, col), filename); throw Eval_Error("Incomplete math expression", File_Position(line, col), filename);
} }
} while (retval && (Symbol("+", true) || Symbol("-", true))); } while (retval && (Symbol("+", true) || Symbol("-", true)));
@@ -1292,7 +1295,7 @@ namespace chaiscript
if (Symbol("*", true) || Symbol("/", true) || Symbol("%", true)) { if (Symbol("*", true) || Symbol("/", true) || Symbol("%", true)) {
do { do {
if (!Dot_Access()) { if (!Dot_Access()) {
throw Parse_Error("Incomplete math expression", File_Position(line, col), filename); throw Eval_Error("Incomplete math expression", File_Position(line, col), filename);
} }
} while (retval && (Symbol("*", true) || Symbol("/", true) || Symbol("%", true))); } while (retval && (Symbol("*", true) || Symbol("/", true) || Symbol("%", true)));
@@ -1316,7 +1319,7 @@ namespace chaiscript
if (Symbol(".")) { if (Symbol(".")) {
do { do {
if (!Value()) { if (!Value()) {
throw Parse_Error("Incomplete dot notation", File_Position(line, col), filename); throw Eval_Error("Incomplete dot notation", File_Position(line, col), filename);
} }
} while (retval && Symbol(".")); } while (retval && Symbol("."));
@@ -1340,7 +1343,7 @@ namespace chaiscript
if (Symbol("&&", true) || Symbol("||", true)) { if (Symbol("&&", true) || Symbol("||", true)) {
do { do {
if (!Comparison()) { if (!Comparison()) {
throw Parse_Error("Incomplete expression", File_Position(line, col), filename); throw Eval_Error("Incomplete expression", File_Position(line, col), filename);
} }
} while (retval && (Symbol("&&", true) || Symbol("||", true))); } while (retval && (Symbol("&&", true) || Symbol("||", true)));
@@ -1364,7 +1367,7 @@ namespace chaiscript
if (Symbol(":")) { if (Symbol(":")) {
do { do {
if (!Expression()) { if (!Expression()) {
throw Parse_Error("Incomplete map pair", File_Position(line, col), filename); throw Eval_Error("Incomplete map pair", File_Position(line, col), filename);
} }
} while (retval && Symbol(":")); } while (retval && Symbol(":"));
@@ -1389,7 +1392,7 @@ namespace chaiscript
if (Symbol("..")) { if (Symbol("..")) {
retval = true; retval = true;
if (!Expression()) { if (!Expression()) {
throw Parse_Error("Incomplete value range", File_Position(line, col), filename); throw Eval_Error("Incomplete value range", File_Position(line, col), filename);
} }
build_match(Token_Type::Value_Range, prev_stack_top); build_match(Token_Type::Value_Range, prev_stack_top);
@@ -1418,7 +1421,7 @@ namespace chaiscript
retval = true; retval = true;
if (Symbol("=", true) || Symbol(":=", true) || Symbol("+=", true) || Symbol("-=", true) || Symbol("*=", true) || Symbol("/=", true)) { if (Symbol("=", true) || Symbol(":=", true) || Symbol("+=", true) || Symbol("-=", true) || Symbol("*=", true) || Symbol("/=", true)) {
if (!Equation()) { if (!Equation()) {
throw Parse_Error("Incomplete equation", match_stack.back()); throw Eval_Error("Incomplete equation", match_stack.back());
} }
build_match(Token_Type::Equation, prev_stack_top); build_match(Token_Type::Equation, prev_stack_top);
@@ -1441,7 +1444,7 @@ namespace chaiscript
has_more = false; has_more = false;
if (Def()) { if (Def()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two function definitions missing line separator", match_stack.back()); throw Eval_Error("Two function definitions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1449,7 +1452,7 @@ namespace chaiscript
} }
else if (If()) { else if (If()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two function definitions missing line separator", match_stack.back()); throw Eval_Error("Two function definitions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1457,7 +1460,7 @@ namespace chaiscript
} }
else if (While()) { else if (While()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two function definitions missing line separator", match_stack.back()); throw Eval_Error("Two function definitions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1465,7 +1468,7 @@ namespace chaiscript
} }
else if (For()) { else if (For()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two function definitions missing line separator", match_stack.back()); throw Eval_Error("Two function definitions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1473,7 +1476,7 @@ namespace chaiscript
} }
else if (Return()) { else if (Return()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two expressions missing line separator", match_stack.back()); throw Eval_Error("Two expressions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1481,7 +1484,7 @@ namespace chaiscript
} }
else if (Break()) { else if (Break()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two expressions missing line separator", match_stack.back()); throw Eval_Error("Two expressions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1489,7 +1492,7 @@ namespace chaiscript
} }
else if (Equation()) { else if (Equation()) {
if (!saw_eol) { if (!saw_eol) {
throw Parse_Error("Two expressions missing line separator", match_stack.back()); throw Eval_Error("Two expressions missing line separator", match_stack.back());
} }
has_more = true; has_more = true;
retval = true; retval = true;
@@ -1525,7 +1528,7 @@ namespace chaiscript
if (Statements()) { if (Statements()) {
if (input_pos != input_end) { if (input_pos != input_end) {
throw Parse_Error("Unparsed input", File_Position(line, col), fname); throw Eval_Error("Unparsed input", File_Position(line, col), fname);
} }
else { else {
build_match(Token_Type::File, 0); build_match(Token_Type::File, 0);

View File

@@ -12,6 +12,8 @@
#define CODE_STRING(x, y) #x ", " #y #define CODE_STRING(x, y) #x ", " #y
#define chaiscript_prelude CODE_STRING(\ #define chaiscript_prelude CODE_STRING(\
def new(x) { eval(type_name(x))(); } \
def clone(x) : function_exists(type_name(x)) { eval(type_name(x))(x); } \
# to_string for Pair()\n\ # to_string for Pair()\n\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \ def to_string(x) : call_exists(first, x) && call_exists(second, x) { \
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \ "<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \
@@ -22,7 +24,7 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \
}\ }\
# Basic to_string function\n\ # Basic to_string function\n\
def to_string(x) { \ def to_string(x) { \
return internal_to_string(x); \ internal_to_string(x); \
}\ }\
# Prints to console with no carriage return\n\ # Prints to console with no carriage return\n\
def puts(x) { \ def puts(x) { \
@@ -41,10 +43,20 @@ def odd(x) { if (x % 2 == 1) { true } else { false } } \
# Returns true if the value is even\n\ # Returns true if the value is even\n\
def even(x) { if (x % 2 == 0) { true } else { false } } \ def even(x) { if (x % 2 == 0) { true } else { false } } \
# Pushes the second value onto the container first value while making a clone of the value\n\ # Pushes the second value onto the container first value while making a clone of the value\n\
def push_back(container, x) { container.push_back_ref(clone(x)) } \n\ def push_back(container, x) : call_exists(push_back_ref, container, x) { container.push_back_ref(clone(x)) } \n\
# Inserts the third value at the position of the second value into the container of the first\n\ # Inserts the third value at the position of the second value into the container of the first\n\
# while making a clone. \n\ # while making a clone. \n\
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\ def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
# Returns the reverse of the given container\n\
def reverse(container) {\
var retval = new(container); \
var r = retro(range(container)); \
while (!r.empty()) { \
retval.push_back(r.front()); \
r.pop_front(); \
} \
retval; \
} \
# Performs the second value function over the container first value\n\ # Performs the second value function over the container first value\n\
def for_each(container, func) : call_exists(range, container) { \ def for_each(container, func) : call_exists(range, container) { \
var range = range(container); \ var range = range(container); \
@@ -54,7 +66,7 @@ def for_each(container, func) : call_exists(range, container) { \
} \ } \
} \ } \
def back_inserter(container) { \ def back_inserter(container) { \
return bind(push_back, container, _); \ bind(push_back, container, _); \
}\ }\
\ \
def map(container, func, inserter) : call_exists(range, container) { \ def map(container, func, inserter) : call_exists(range, container) { \
@@ -64,11 +76,11 @@ def map(container, func, inserter) : call_exists(range, container) { \
range.pop_front(); \ range.pop_front(); \
} \ } \
} \ } \
# Performs the second value function over the container first value. Creates a new Vector with the results\n\ # Performs the second value function over the container first value. Creates a new container with the results\n\
def map(container, func) { \ def map(container, func) { \
var retval = Vector();\ var retval = new(container); \
map(container, func, back_inserter(retval));\ map(container, func, back_inserter(retval));\
return retval;\ retval;\
}\ }\
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\ # Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
def foldl(container, func, initial) : call_exists(range, container){ \ def foldl(container, func, initial) : call_exists(range, container){ \
@@ -84,7 +96,7 @@ def foldl(container, func, initial) : call_exists(range, container){ \
def sum(container) { foldl(container, `+`, 0.0) } \ def sum(container) { foldl(container, `+`, 0.0) } \
# Returns the product of the elements of the given value\n\ # Returns the product of the elements of the given value\n\
def product(container) { foldl(container, `*`, 1.0) } \ def product(container) { foldl(container, `*`, 1.0) } \
# Returns a new Vector with the elements of the first value concatenated with the elements of the second value\n\ # Returns a new container with the elements of the first value concatenated with the elements of the second value\n\
def concat(x, y) : call_exists(clone, x) { \ def concat(x, y) : call_exists(clone, x) { \
var retval = x; \ var retval = x; \
var len = y.size(); \ var len = y.size(); \
@@ -104,11 +116,11 @@ def take(container, num, inserter) : call_exists(range, container) { \
--i; \ --i; \
} \ } \
} \ } \
# Returns a new Vector with the given number of elements taken from the container\n\ # Returns a new container with the given number of elements taken from the container\n\
def take(container, num) {\ def take(container, num) {\
var retval = Vector(); \ var retval = new(container); \
take(container, num, back_inserter(retval)); \ take(container, num, back_inserter(retval)); \
return retval; \ retval; \
}\ }\
def take_while(container, f, inserter) : call_exists(range, container) { \ def take_while(container, f, inserter) : call_exists(range, container) { \
var r = range(container); \ var r = range(container); \
@@ -117,11 +129,11 @@ def take_while(container, f, inserter) : call_exists(range, container) { \
r.pop_front(); \ r.pop_front(); \
} \ } \
} \ } \
# Returns a new Vector with the given elements match the second value function\n\ # Returns a new container with the given elements match the second value function\n\
def take_while(container, f) {\ def take_while(container, f) {\
var retval = Vector(); \ var retval = new(container); \
take_while(container, f, back_inserter(retval)); \ take_while(container, f, back_inserter(retval)); \
return retval;\ retval;\
}\ }\
def drop(container, num, inserter) : call_exists(range, container) { \ def drop(container, num, inserter) : call_exists(range, container) { \
var r = range(container); \ var r = range(container); \
@@ -135,11 +147,11 @@ def drop(container, num, inserter) : call_exists(range, container) { \
r.pop_front(); \ r.pop_front(); \
} \ } \
} \ } \
# Returns a new Vector with the given number of elements dropped from the given container \n\ # Returns a new container with the given number of elements dropped from the given container \n\
def drop(container, num) {\ def drop(container, num) {\
var retval = Vector(); \ var retval = new(container); \
drop(container, num, back_inserter(retval)); \ drop(container, num, back_inserter(retval)); \
return retval; \ retval; \
}\ }\
def drop_while(container, f, inserter) : call_exists(range, container) { \ def drop_while(container, f, inserter) : call_exists(range, container) { \
var r = range(container); \ var r = range(container); \
@@ -151,11 +163,11 @@ def drop_while(container, f, inserter) : call_exists(range, container) { \
r.pop_front(); \ r.pop_front(); \
} \ } \
} \ } \
# Returns a new Vector with the given elements dropped that match the second value function\n\ # Returns a new container with the given elements dropped that match the second value function\n\
def drop_while(container, f) {\ def drop_while(container, f) {\
var retval = Vector(); \ var retval = new(container); \
drop_while(container, f, back_inserter(retval)); \ drop_while(container, f, back_inserter(retval)); \
return retval; \ retval; \
}\ }\
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\ # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \ def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \
@@ -196,9 +208,9 @@ def filter(container, f, inserter) : call_exists(range, container) { \
} \ } \
# Returns a new Vector which match the second value function\n\ # Returns a new Vector which match the second value function\n\
def filter(container, f) { \ def filter(container, f) { \
var retval = Vector(); \ var retval = new(container); \
filter(container, f, back_inserter(retval));\ filter(container, f, back_inserter(retval));\
return retval;\ retval;\
}\ }\
def generate_range(x, y, inserter) { \ def generate_range(x, y, inserter) { \
var i = x; \ var i = x; \
@@ -211,7 +223,7 @@ def generate_range(x, y, inserter) { \
def generate_range(x, y) { \ def generate_range(x, y) { \
var retval = Vector(); \ var retval = Vector(); \
generate_range(x,y,back_inserter(retval)); \ generate_range(x,y,back_inserter(retval)); \
return retval; \ retval; \
}\ }\
# Returns a new Vector with the first value to the second value as its elements\n\ # Returns a new Vector with the first value to the second value as its elements\n\
def collate(x, y) { \ def collate(x, y) { \
@@ -230,7 +242,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
def zip_with(f, x, y) { \ def zip_with(f, x, y) { \
var retval = Vector(); \ var retval = Vector(); \
zip_with(f,x,y,back_inserter(retval)); \ zip_with(f,x,y,back_inserter(retval)); \
return retval;\ retval;\
}\ }\
# Returns a new Vector which joins matching elements of the first and second\n\ # Returns a new Vector which joins matching elements of the first and second\n\
def zip(x, y) { \ def zip(x, y) { \
@@ -238,28 +250,36 @@ def zip(x, y) { \
}\ }\
# Returns the position of the second value string in the first value string\n\ # Returns the position of the second value string in the first value string\n\
def find(str, substr) { \ def find(str, substr) { \
return int(find(str, substr, size_t(0))); \ int(find(str, substr, size_t(0))); \
} \ } \
# Returns the position of last match of the second value string in the first value string\n\ # Returns the position of last match of the second value string in the first value string\n\
def rfind(str, substr) { \ def rfind(str, substr) { \
return int(rfind(str, substr, size_t(-1))); \ int(rfind(str, substr, size_t(-1))); \
} \ } \
# Returns the position of the first match of elements in the second value string in the first value string\n\ # Returns the position of the first match of elements in the second value string in the first value string\n\
def find_first_of(str, list) { \ def find_first_of(str, list) { \
return int(find_first_of(str, list, size_t(0))); \ int(find_first_of(str, list, size_t(0))); \
} \ } \
# Returns the position of the last match of elements in the second value string in the first value string\n\ # Returns the position of the last match of elements in the second value string in the first value string\n\
def find_last_of(str, list) { \ def find_last_of(str, list) { \
return int(find_last_of(str, list, size_t(-1))); \ int(find_last_of(str, list, size_t(-1))); \
} \ } \
# Returns the position of the first non-matching element in the second value string in the first value string\n\ # Returns the position of the first non-matching element in the second value string in the first value string\n\
def find_first_not_of(str, list) { \ def find_first_not_of(str, list) { \
return int(find_first_not_of(str, list, size_t(0))); \ int(find_first_not_of(str, list, size_t(0))); \
} \ } \
# Returns the position of the last non-matching element in the second value string in the first value string\n\ # Returns the position of the last non-matching element in the second value string in the first value string\n\
def find_last_not_of(str, list) { \ def find_last_not_of(str, list) { \
return int(find_last_not_of(str, list, size_t(-1))); \ int(find_last_not_of(str, list, size_t(-1))); \
} \
def ltrim(str) { \
drop_while(str, fun(x) { x == ' ' || x == '\t' }); \
} \
def rtrim(str) { \
reverse(drop_while(reverse(str), fun(x) { x == ' ' || x == '\t' })); \
} \
def trim(str) { \
ltrim(rtrim(str)); \
} \ } \
) )
#endif /* CHAISCRIPT_PRELUDE_HPP_ */ #endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="chai-example"
ProjectGUID="{CE422E94-B360-4588-8C65-6A9BE80798F9}"
RootNamespace="chaiexample"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="C:\Programming\chaiscript\trunk\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
CharacterSet="0"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\src\example.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -8,4 +8,12 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Programming\Boost\include\boost-1_38&quot;" AdditionalIncludeDirectories="&quot;C:\Programming\Boost\include\boost-1_38&quot;"
/> />
<Tool
Name="VCLibrarianTool"
AdditionalLibraryDirectories="C:\Programming\Boost\lib"
/>
<Tool
Name="VCLinkerTool"
AdditionalLibraryDirectories="C:\Programming\Boost\lib"
/>
</VisualStudioPropertySheet> </VisualStudioPropertySheet>

View File

@@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008 # Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vcproj", "{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vcproj", "{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chai-example", "..\chai-example\chai-example.vcproj", "{CE422E94-B360-4588-8C65-6A9BE80798F9}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@@ -13,6 +15,10 @@ Global
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.Build.0 = Debug|Win32 {46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.Build.0 = Debug|Win32
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.ActiveCfg = Release|Win32 {46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.ActiveCfg = Release|Win32
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.Build.0 = Release|Win32 {46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.Build.0 = Release|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Debug|Win32.ActiveCfg = Debug|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Debug|Win32.Build.0 = Debug|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.ActiveCfg = Release|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -122,7 +122,7 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="3" Optimization="3"
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\dispatchkit&quot;;&quot;$(ProjectDir)\..\..\chaiscript&quot;" AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2" RuntimeLibrary="2"
EnableFunctionLevelLinking="true" EnableFunctionLevelLinking="true"
@@ -229,6 +229,14 @@
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp" RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
> >
</File> </File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\function_call_detail.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\handle_return.hpp"
>
</File>
<File <File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_constructors.hpp" RelativePath="..\..\include\chaiscript\dispatchkit\proxy_constructors.hpp"
> >
@@ -237,6 +245,10 @@
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions.hpp" RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions.hpp"
> >
</File> </File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions_detail.hpp"
>
</File>
<File <File
RelativePath="..\..\include\chaiscript\dispatchkit\register_function.hpp" RelativePath="..\..\include\chaiscript\dispatchkit\register_function.hpp"
> >

View File

@@ -2,7 +2,7 @@ var i = 0
if (i == 0) { if (i == 0) {
print("i is 0") print("i is 0")
} }
elseif (i == 1) { else if (i == 1) {
print("i is 1") print("i is 1")
} }
else { else {

View File

@@ -27,9 +27,9 @@ struct System
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks; std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name, void add_callback(const std::string &t_name,
boost::shared_ptr<dispatchkit::Proxy_Function> t_func) const chaiscript::Proxy_Function &t_func)
{ {
m_callbacks[t_name] = dispatchkit::build_function_caller<std::string (const std::string &)>(t_func); m_callbacks[t_name] = chaiscript::functor<std::string (const std::string &)>(t_func);
} }
@@ -45,48 +45,92 @@ struct System
} }
}; };
void take_shared_ptr(const boost::shared_ptr<std::string> &p)
{
std::cout << *p << std::endl;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
using namespace chaiscript;
ChaiScript chai;
chaiscript::ChaiScript_Engine chai;
//Create a new system object and share it with the chaiscript engine //Create a new system object and share it with the chaiscript engine
System system; System system;
chai.get_eval_engine().add_object("system", boost::ref(system)); chai.add(var(&system), "system");
//Register the two methods of the System structure. //Register the two methods of the System structure.
dispatchkit::register_function(chai.get_eval_engine(), &System::add_callback, "add_callback"); chai.add(fun(&System::add_callback), "add_callback");
dispatchkit::register_function(chai.get_eval_engine(), &System::do_callbacks, "do_callbacks"); chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// Let's use chaiscript to add a new lambda callback to our system. // Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application // The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a // in the "add_callback" function of struct System the chaiscript function is converted into a
// boost::function, so it can be handled and called easily and type-safely // boost::function, so it can be handled and called easily and type-safely
chai.evaluate_string("system.add_callback('#1', fun(x) { 'Callback1 ' + x });"); chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
// Because we are sharing the "system" object with the chaiscript engine we have equal // Because we are sharing the "system" object with the chaiscript engine we have equal
// access to it both from within chaiscript and from C++ code // access to it both from within chaiscript and from C++ code
system.do_callbacks("TestString"); system.do_callbacks("TestString");
chai.evaluate_string("system.do_callbacks(\"TestString\");"); chai.eval("system.do_callbacks(\"TestString\");");
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which // The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
// version we want to register. One way to do this is to create a typedef of the function pointer // version we want to register. One way to do this is to create a typedef of the function pointer
// then cast your function to that typedef. // then cast your function to that typedef.
typedef void (*PlainLog)(const std::string &); typedef void (*PlainLog)(const std::string &);
typedef void (*ModuleLog)(const std::string &, const std::string &); typedef void (*ModuleLog)(const std::string &, const std::string &);
dispatchkit::register_function(chai.get_eval_engine(), PlainLog(&log), "log"); chai.add(fun(PlainLog(&log)), "log");
dispatchkit::register_function(chai.get_eval_engine(), ModuleLog(&log), "log"); chai.add(fun(ModuleLog(&log)), "log");
chai.evaluate_string("log('Test Message')"); chai.eval("log(\"Test Message\")");
chai.evaluate_string("log('Test Module', 'Test Message');");
// A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register any boost::function as a system function, in this //Finally, it is possible to register any boost::function as a system function, in this
//way, we can, for instance add a bound member function to the system //way, we can, for instance add a bound member function to the system
chai.get_eval_engine().register_function(boost::function<void ()>(boost::bind(&System::do_callbacks, boost::ref(system), "Bound Test")), "do_callbacks"); chai.add(fun(boost::function<void ()>(boost::bind(&System::do_callbacks, boost::ref(system), "Bound Test"))), "do_callbacks");
//Call bound version of do_callbacks //Call bound version of do_callbacks
chai.evaluate_string("do_callbacks()"); chai("do_callbacks()");
boost::function<void ()> caller = chai.functor<void ()>("fun() { system.do_callbacks(\"From Functor\"); }");
caller();
//If we would like a type-safe return value from all call, we can use
//the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << std::endl;
//Add a new variable
chai("var scripti = 15");
//We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << std::endl;
scripti *= 2;
std::cout << "scripti (updated): " << scripti << std::endl;
chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediatly
int x = chai.functor<int (int, int)>("fun (x, y) { return x + y; }")(5, 6);
log("Functor test output", boost::lexical_cast<std::string>(x));
//Ability to create our own container types when needed. std::vector and std::map are
//mostly supported currently
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
chai("dump_system()");
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
} }

View File

@@ -17,14 +17,14 @@ void print_help() {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::string input; std::string input;
chaiscript::ChaiScript_Engine chai; chaiscript::ChaiScript chai;
if (argc < 2) { if (argc < 2) {
std::cout << "eval> "; std::cout << "eval> ";
std::getline(std::cin, input); std::getline(std::cin, input);
while (input != "quit") { while (input != "quit") {
dispatchkit::Boxed_Value val; chaiscript::Boxed_Value val;
if (input == "help") { if (input == "help") {
print_help(); print_help();
@@ -32,24 +32,18 @@ int main(int argc, char *argv[]) {
else { else {
try { try {
//First, we evaluate it //First, we evaluate it
val = chai.evaluate_string(input); val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user //Then, we try to print the result of the evaluation to the user
if (val.get_type_info().m_bare_type_info && *(val.get_type_info().m_bare_type_info) != typeid(void)) { if (val.get_type_info().m_bare_type_info && *(val.get_type_info().m_bare_type_info) != typeid(void)) {
try { try {
dispatchkit::dispatch(chai.get_eval_engine().get_function("print"), dispatchkit::Param_List_Builder() << val); chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
} }
catch (...) { catch (...) {
//If we can't, do nothing //If we can't, do nothing
} }
} }
} }
catch (chaiscript::Parse_Error &pe) {
std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl;
}
catch (chaiscript::Eval_Error &ee) {
std::cout << ee.reason << std::endl;
}
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;
} }
@@ -63,23 +57,7 @@ int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
std::string filename(argv[i]); std::string filename(argv[i]);
try { try {
dispatchkit::Boxed_Value val = chai.evaluate_file(argv[i]); chaiscript::Boxed_Value val = chai.eval_file(argv[i]);
}
catch (chaiscript::Parse_Error &pe) {
if (filename != std::string("__EVAL__")) {
std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl;
}
else {
std::cout << pe.reason << std::endl;
}
}
catch (chaiscript::Eval_Error &ee) {
if (filename != std::string("__EVAL__")) {
std::cout << ee.reason << " in '" << ee.location->filename << "' at " << ee.location->start.line << ", " << ee.location->start.column << std::endl;
}
else {
std::cout << ee.reason << std::endl;
}
} }
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;

2
unittests/float.chai Normal file
View File

@@ -0,0 +1,2 @@
print(1.2)
print(.5)

2
unittests/float.txt Normal file
View File

@@ -0,0 +1,2 @@
1.2
0.5

View File

@@ -2,10 +2,10 @@ var i = 3
if (i == 2) { if (i == 2) {
print("2") print("2")
} }
elseif (i == 4) { else if (i == 4) {
print("4") print("4")
} }
elseif (i == 3) { else if (i == 3) {
print("3") print("3")
} }

View File

@@ -2,7 +2,7 @@ var i = 3
if (i == 2) { if (i == 2) {
print("2") print("2")
} }
elseif (i == 4) { else if (i == 4) {
print("4") print("4")
} }
else { else {

View File

@@ -0,0 +1,3 @@
var addit = fun(x, y) { return x+y }
print(3.addit(4))

View File

@@ -0,0 +1 @@
7

4
unittests/range.chai Normal file
View File

@@ -0,0 +1,4 @@
var x = [1, 2, 3, 4]
var r = range(x)
r.pop_front()
print(r.front())

1
unittests/range.txt Normal file
View File

@@ -0,0 +1 @@
2

View File

@@ -0,0 +1,4 @@
var x = [1, 2, 3, 4]
var r = range(x)
r.pop_back()
print(r.back())

1
unittests/range_back.txt Normal file
View File

@@ -0,0 +1 @@
3

4
unittests/retro.chai Normal file
View File

@@ -0,0 +1,4 @@
var x = [1, 2, 3, 4]
var r = retro(range(x))
r.pop_front()
print(r.front())

1
unittests/retro.txt Normal file
View File

@@ -0,0 +1 @@
3

3
unittests/use.chai Normal file
View File

@@ -0,0 +1,3 @@
use("unittests/use.inc")
greet()

3
unittests/use.inc Normal file
View File

@@ -0,0 +1,3 @@
def greet {
print("hello")
}

1
unittests/use.txt Normal file
View File

@@ -0,0 +1 @@
hello