Compare commits

..

20 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
28 changed files with 955 additions and 647 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

@@ -87,7 +87,8 @@ namespace chaiscript
*/ */
struct Eval_Error : public std::runtime_error { struct Eval_Error : public std::runtime_error {
std::string reason; std::string reason;
File_Position position; File_Position start_position;
File_Position end_position;
const char *filename; const char *filename;
Eval_Error(const std::string &why, const File_Position &where, const char *fname) : Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
@@ -95,7 +96,7 @@ namespace chaiscript
(std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") + (std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " + + "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"), boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), position(where), filename(fname) reason(why), start_position(where), end_position(where), filename(fname)
{ } { }
Eval_Error(const std::string &why, const TokenPtr &where) Eval_Error(const std::string &why, const TokenPtr &where)
@@ -103,7 +104,7 @@ namespace chaiscript
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") + (std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " + "at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
boost::lexical_cast<std::string>(where->start.column) + ")"), boost::lexical_cast<std::string>(where->start.column) + ")"),
reason(why), position(where->start), filename(where->filename) { reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
} }
virtual ~Eval_Error() throw() {} virtual ~Eval_Error() throw() {}

View File

@@ -635,7 +635,7 @@ namespace chaiscript
Proxy_Function f = boxed_cast<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())) static boost::shared_ptr<Dispatch_Engine> bootstrap2(boost::shared_ptr<Dispatch_Engine> e = boost::shared_ptr<Dispatch_Engine> (new Dispatch_Engine()))

View File

@@ -203,10 +203,10 @@ namespace chaiscript
{ {
assignable_type<ContainerType>(type, m); assignable_type<ContainerType>(type, m);
m->add(fun(&ContainerType::size), "size"); m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::size), "size");
m->add(fun(&ContainerType::max_size), "max_size"); m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::max_size), "max_size");
m->add(fun(&ContainerType::empty), "empty"); m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun(&ContainerType::clear), "clear"); m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
return m; return m;
} }
@@ -387,7 +387,7 @@ namespace chaiscript
ModulePtr unique_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module())) ModulePtr unique_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
associative_container_type<ContainerType>(type, m); associative_container_type<ContainerType>(type, m);
m->add(fun(&ContainerType::count), "count"); m->add(fun<size_t (ContainerType::*)(const typename ContainerType::key_type &) const>(&ContainerType::count), "count");
return m; return m;
} }

View File

@@ -97,11 +97,6 @@ namespace chaiscript
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,10 +111,15 @@ namespace chaiscript
*/ */
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)
); );
@@ -135,7 +135,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj) 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>()))
@@ -164,7 +164,7 @@ namespace chaiscript
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)
); );
@@ -192,7 +192,7 @@ namespace chaiscript
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>()))
@@ -219,6 +219,12 @@ namespace chaiscript
*/ */
void cull() void cull()
{ {
++m_cullcount;
if (m_cullcount % 10 != 0)
{
return;
}
std::map<const void *, Data >::iterator itr = m_ptrs.begin(); std::map<const void *, Data >::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end()) while (itr != m_ptrs.end())
@@ -235,6 +241,7 @@ namespace chaiscript
} }
std::map<const void *, Data > m_ptrs; std::map<const void *, Data > m_ptrs;
int m_cullcount;
}; };
public: public:
@@ -324,175 +331,178 @@ namespace chaiscript
}; };
// Cast_Helper helper classes namespace detail
{
// Cast_Helper helper classes
/** /**
* Generic Cast_Helper, for casting to any type * Generic Cast_Helper, for casting to any type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper struct Cast_Helper
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (!ob.get_type_info().m_is_const) if (ob.is_ref())
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); if (!ob.get_type_info().m_is_const)
{
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::any_cast<boost::reference_wrapper<const Result> >(ob.get()); return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
} };
};
/** /**
* Cast_Helper for casting to a const & type * Cast_Helper for casting to a const & type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<const Result &> struct Cast_Helper<const Result &>
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (!ob.get_type_info().m_is_const) if (ob.is_ref())
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); if (!ob.get_type_info().m_is_const)
{
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::any_cast<boost::reference_wrapper<const Result> >(ob.get()); return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
} };
};
/** /**
* Cast_Helper for casting to a const * type * Cast_Helper for casting to a const * type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<const Result *> struct Cast_Helper<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (!ob.get_type_info().m_is_const) if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
{
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 {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
/**
* Cast_Helper for casting to a * type
*/
template<typename Result>
struct Cast_Helper<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{ {
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 { } else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer(); return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} }
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} }
} };
};
/** /**
* Cast_Helper for casting to a * type * Cast_Helper for casting to a & type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<Result *> struct Cast_Helper<Result &>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer(); if (ob.is_ref())
} else { {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get(); return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
} }
} };
};
/** /**
* Cast_Helper for casting to a & type * Cast_Helper for casting to a boost::shared_ptr<> type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<Result &> struct Cast_Helper<typename boost::shared_ptr<Result> >
{
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get()); return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} }
} };
};
/** /**
* Cast_Helper for casting to a boost::shared_ptr<> type * Cast_Helper for casting to a boost::shared_ptr<> type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<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()); typedef typename boost::shared_ptr<Result> Result_Type;
}
};
/** static Result_Type cast(const Boxed_Value &ob)
* Cast_Helper for casting to a boost::shared_ptr<> type {
*/ return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
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)
/**
* Cast_Helper for casting to a Boxed_Value type
*/
template<>
struct Cast_Helper<Boxed_Value>
{ {
return boost::any_cast<boost::shared_ptr<Result> >(ob.get()); typedef const Boxed_Value & Result_Type;
}
};
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
/**
/** * Cast_Helper for casting to a const Boxed_Value & type
* Cast_Helper for casting to a Boxed_Value type */
*/ template<>
template<> struct Cast_Helper<const Boxed_Value &>
struct Cast_Helper<Boxed_Value>
{
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return ob; typedef const Boxed_Value & Result_Type;
}
};
/** static Result_Type cast(const Boxed_Value &ob)
* Cast_Helper for casting to a const Boxed_Value & type {
*/ return ob;
template<> }
struct Cast_Helper<const Boxed_Value &> };
{ }
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &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,
@@ -530,10 +540,10 @@ namespace chaiscript
* 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));
} }
@@ -669,19 +679,22 @@ namespace chaiscript
bool m_isfloat; bool m_isfloat;
}; };
/** namespace detail
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value {
*/ /**
template<> * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
struct Cast_Helper<Boxed_POD_Value> */
{ template<>
typedef Boxed_POD_Value Result_Type; struct Cast_Helper<Boxed_POD_Value>
static Result_Type cast(const Boxed_Value &ob)
{ {
return Boxed_POD_Value(ob); typedef Boxed_POD_Value Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
}
template<typename T> template<typename T>
Boxed_Value var(T t) Boxed_Value var(T t)
@@ -690,7 +703,7 @@ namespace chaiscript
} }
/** /**
* Return true if the two Boxed_Value's share the same internal type * Return true if the two Boxed_Values share the same internal type
*/ */
static bool type_match(Boxed_Value l, Boxed_Value r) static bool type_match(Boxed_Value l, Boxed_Value r)
{ {

View File

@@ -94,7 +94,12 @@ namespace chaiscript
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
{
return -1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec; typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
@@ -103,7 +108,7 @@ namespace chaiscript
while (begin != end) while (begin != end)
{ {
if (begin->second->types_match(types)) if (begin->second->call_match(vals))
{ {
return true; return true;
} else { } else {
@@ -124,6 +129,23 @@ namespace chaiscript
}; };
/**
* 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() {}
};
/** /**
* Main class for the dispatchkit. Handles management * Main class for the dispatchkit. Handles management
* of the object stack, functions and registered types. * of the object stack, functions and registered types.
@@ -133,12 +155,13 @@ namespace chaiscript
public: public:
typedef std::map<std::string, chaiscript::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());
} }
/** /**
@@ -146,6 +169,7 @@ namespace chaiscript
*/ */
bool add(const 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);
} }
@@ -163,12 +187,13 @@ namespace chaiscript
*/ */
void add(const Boxed_Value &obj, const std::string &name) void add(const Boxed_Value &obj, const std::string &name)
{ {
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;
} }
} }
@@ -181,7 +206,8 @@ namespace chaiscript
*/ */
void add_object(const std::string &name, const Boxed_Value &obj) void add_object(const std::string &name, const Boxed_Value &obj)
{ {
m_scopes.back()[name] = Boxed_Value(obj); validate_object_name(name);
m_scopes->back()[name] = Boxed_Value(obj);
} }
/** /**
@@ -189,7 +215,7 @@ namespace chaiscript
*/ */
void new_scope() void new_scope()
{ {
m_scopes.push_back(Scope()); m_scopes->push_back(Scope());
} }
/** /**
@@ -197,9 +223,9 @@ namespace chaiscript
*/ */
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");
} }
@@ -218,10 +244,16 @@ namespace chaiscript
* \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());
} }
/** /**
@@ -236,16 +268,16 @@ namespace chaiscript
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, 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())
{ {
@@ -309,10 +341,21 @@ namespace chaiscript
/** /**
* Return a function by name * Return a function by name
*/ */
std::vector<std::pair<std::string, std::multimap<std::string, 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();
} }
/** /**
@@ -323,35 +366,22 @@ namespace chaiscript
return std::vector<std::pair<std::string, 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, 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, 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, Proxy_Function >::mapped_type>(get_object(t_name)))
);
} catch (const bad_boxed_cast &) {
} catch (const std::range_error &) {
}
} }
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);
funcs.insert(funcs.end(), range.first, range.second);
return funcs;
} }
/** /**
@@ -377,11 +407,12 @@ namespace chaiscript
return true; return true;
} }
std::deque<Scope> m_scopes; Stack m_scopes;
std::multimap<std::string, 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;
}; };
/** /**

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(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_hpp__ #ifndef __function_call_hpp__
#define __function_call_hpp__ #define __function_call_hpp__
@@ -20,50 +13,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "function_call_detail.hpp"
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, 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, 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 chaiscript namespace chaiscript
{ {
@@ -80,7 +30,7 @@ namespace chaiscript
functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs) functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
{ {
FunctionType *p=0; FunctionType *p=0;
return build_function_caller_helper(p, funcs); return detail::build_function_caller_helper(p, funcs);
} }
/** /**
@@ -118,39 +68,5 @@ namespace chaiscript
} }
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* 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 #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

@@ -26,7 +26,7 @@ namespace chaiscript
Proxy_Function constructor() Proxy_Function constructor()
{ {
T *f = 0; T *f = 0;
return (build_constructor_(f)); return (detail::build_constructor_(f));
} }
} }
@@ -35,28 +35,31 @@ namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
/** namespace detail
* A constructor function, used for creating a new object {
* of a given type with a given set of params /**
*/ * A constructor function, used for creating a new object
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) > * of a given type with a given set of params
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) */
{ template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, 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) ));
}
/** /**
* Helper function for build a constructor function * Helper function for build a constructor function
* example: * example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass"); * dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \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) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param))) Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param)); typedef boost::shared_ptr<Class> (sig)(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)>)))); return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
} }
}
} }
#endif #endif

View File

@@ -4,109 +4,22 @@
// 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) ,chaiscript::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) chaiscript::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 chaiscript 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());
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
Boxed_Value operator()(const boost::function<boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
Boxed_Value operator()(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 &>
{
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<<
@@ -138,30 +51,6 @@ namespace chaiscript
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 chaiscript
{
/** /**
* 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++
@@ -177,7 +66,48 @@ namespace chaiscript
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_Base &) 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;
}; };
@@ -209,7 +139,8 @@ namespace chaiscript
int t_arity=-1, int t_arity=-1,
const std::string &t_description = "", const std::string &t_description = "",
const Proxy_Function &t_guard = 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))
{ {
} }
@@ -218,10 +149,10 @@ namespace chaiscript
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() {}
@@ -243,23 +174,14 @@ namespace chaiscript
} }
} }
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
@@ -284,10 +206,30 @@ namespace chaiscript
} }
} }
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;
Proxy_Function m_guard; Proxy_Function m_guard;
std::vector<Type_Info> m_types;
}; };
/** /**
@@ -309,7 +251,7 @@ namespace chaiscript
public: public:
Bound_Function(const 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()))
{ {
} }
@@ -320,10 +262,9 @@ namespace chaiscript
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)
@@ -343,7 +284,7 @@ namespace chaiscript
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;
@@ -356,7 +297,7 @@ namespace chaiscript
} }
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;
} }
@@ -374,6 +315,11 @@ namespace chaiscript
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 "";
@@ -382,6 +328,7 @@ namespace chaiscript
private: private:
Proxy_Function m_f; Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity;
}; };
/** /**
@@ -394,7 +341,7 @@ namespace chaiscript
{ {
public: public:
Proxy_Function_Impl(const boost::function<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))
{ {
} }
@@ -417,14 +364,18 @@ namespace chaiscript
virtual std::vector<Type_Info> get_param_types() const virtual std::vector<Type_Info> get_param_types() const
{ {
Func *f = 0; return m_types;
return build_param_type_list(f);
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual int get_arity() const
{ {
Func *f = 0; return m_types.size() - 1;
return compare_types(f, types); }
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
@@ -434,6 +385,8 @@ namespace chaiscript
private: private:
boost::function<Func> m_f; boost::function<Func> m_f;
Func *m_dummy_func;
std::vector<Type_Info> m_types;
}; };
/** /**
@@ -465,7 +418,10 @@ namespace chaiscript
++itr) ++itr)
{ {
try { try {
return (*itr->second)(plist); if (itr->second->filter(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 &) {
@@ -479,70 +435,5 @@ namespace chaiscript
} }
} }
# 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(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(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

@@ -16,71 +16,86 @@
namespace chaiscript namespace chaiscript
{ {
template<typename T> namespace detail
Proxy_Function fun(const boost::function<T> &f) {
{ /**
return Proxy_Function(new Proxy_Function_Impl<T>(f)); * Helper function for register_member function
} */
template<typename T, typename Class>
T &get_member(T Class::* m, Class *obj)
{
return (obj->*m);
}
template<typename T>
Proxy_Function fun_helper(const boost::function<T> &f)
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
/** /**
* Helper function for register_member function * Automatically create a get_member helper function for an object
*/ * to allow for runtime dispatched access to public data members
template<typename T, typename Class> * for example, the case of std::pair<>::first and std::pair<>::second
T &get_member(T Class::* m, Class *obj) */
{ template<typename T, typename Class>
return (obj->*m); Proxy_Function fun_helper(T Class::* m)
} {
return fun_helper(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
/** }
* Automatically create a get_member helper function for an object }
* to allow for runtime dispatched access to public data members
* for example, the case of std::pair<>::first and std::pair<>::second
*/
template<typename T, typename Class>
Proxy_Function fun(T Class::* m)
{
return fun(boost::function<T& (Class *)>(boost::bind(&get_member<T, Class>, m, _1)));
}
} }
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 ) #define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#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 chaiscript namespace chaiscript
{ {
/** namespace detail
* Register a global function of n parameters with name {
*/ /**
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> * Register a global function of n parameters with name
Proxy_Function fun(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param))) */
{ template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
return fun(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f)); Proxy_Function fun_helper(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
} {
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)>
Proxy_Function fun(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))) Proxy_Function fun_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
return fun(boost::function<Ret (Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f)); 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)>
Proxy_Function fun(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const) Proxy_Function fun_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const)
{ {
return fun(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f)); return fun_helper(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
} }
}
} }
#endif #endif

View File

@@ -77,57 +77,71 @@ namespace chaiscript
bool m_is_unknown; bool m_is_unknown;
}; };
/** namespace detail
* Helper used to create a Type_Info object {
*/ /**
template<typename T> * Helper used to create a Type_Info object
struct Get_Type_Info */
{ template<typename T>
static Type_Info get() struct Get_Type_Info
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, static Type_Info get()
boost::is_void<T>::value, {
&typeid(T), return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type)); boost::is_void<T>::value,
} &typeid(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::shared_ptr<T> > struct Get_Type_Info<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, static Type_Info get()
boost::is_void<T>::value, {
&typeid(boost::shared_ptr<T> ), return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type)); boost::is_void<T>::value,
} &typeid(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<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, static Type_Info get()
boost::is_void<T>::value, {
&typeid(boost::reference_wrapper<T> ), return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type)); 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>
struct Get_Type_Info<boost::reference_wrapper<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(boost::reference_wrapper<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
}
template<typename T> template<typename T>
Type_Info user_type(T) Type_Info user_type(T)
{ {
return Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
template<typename T> template<typename T>
Type_Info user_type() Type_Info user_type()
{ {
return Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }

View File

@@ -19,18 +19,27 @@ 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 * Evaluates the given string in by parsing it and running the results through the evaluator
*/ */
Boxed_Value do_eval(const std::string &input, const char *filename = "__EVAL__") { Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__") {
//debug_print(tokens); //debug_print(tokens);
Boxed_Value value; Boxed_Value value;
parser.clear_match_stack(); 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 { try {
if (parser.parse(input, filename)) { if (parser.parse(input, loaded_files.find(filename)->c_str())) {
//parser.show_match_stack(); //parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast()); value = eval_token<Eval_Engine>(engine, parser.ast());
} }
@@ -49,6 +58,14 @@ namespace chaiscript
return do_eval(boxed_cast<std::string>(vals.at(0))); 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() {
@@ -117,12 +134,11 @@ namespace chaiscript
/** /**
* 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();
@@ -141,6 +157,24 @@ namespace chaiscript
*/ */
void build_eval_system() { void build_eval_system() {
using namespace bootstrap; using namespace bootstrap;
engine.add_reserved_word("def");
engine.add_reserved_word("fun");
engine.add_reserved_word("while");
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.add(Bootstrap::bootstrap()); 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 ()>(boost::bind(&dump_system, boost::ref(engine)))), "dump_system");
@@ -150,12 +184,16 @@ namespace chaiscript
engine.add(fun(boost::function<std::string (Boxed_Value)>(boost::bind(&chaiscript::type_name, boost::ref(engine), _1))), engine.add(fun(boost::function<std::string (Boxed_Value)>(boost::bind(&chaiscript::type_name, boost::ref(engine), _1))),
"type_name"); "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(vector_type<std::vector<Boxed_Value> >("Vector"));
engine.add(string_type<std::string>("string")); engine.add(string_type<std::string>("string"));
engine.add(map_type<std::map<std::string, Boxed_Value> >("Map")); engine.add(map_type<std::map<std::string, Boxed_Value> >("Map"));
engine.add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair")); 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( engine.add(Proxy_Function(
new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::internal_eval, boost::ref(*this), _1), 1)), "eval"); new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::internal_eval, boost::ref(*this), _1), 1)), "eval");
@@ -176,7 +214,7 @@ namespace chaiscript
/** /**
* Loads the file specified by filename, evaluates it, and returns the result * Loads the file specified by filename, evaluates it, and returns the result
*/ */
Boxed_Value eval_file(const char *filename) { Boxed_Value eval_file(const std::string &filename) {
return do_eval(load_file(filename), filename); return do_eval(load_file(filename), filename);
} }
@@ -184,7 +222,7 @@ namespace chaiscript
* Loads the file specified by filename, evaluates it, and returns the as the specified type * Loads the file specified by filename, evaluates it, and returns the as the specified type
*/ */
template<typename T> template<typename T>
T eval_file(const char *filename) { T eval_file(const std::string &filename) {
return boxed_cast<T>(do_eval(load_file(filename), filename)); return boxed_cast<T>(do_eval(load_file(filename), filename));
} }
}; };

View File

@@ -171,7 +171,12 @@ namespace chaiscript
*/ */
template <typename Eval_System> template <typename Eval_System>
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, 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);
} }
@@ -405,10 +410,10 @@ namespace chaiscript
Boxed_Value retval; Boxed_Value retval;
Param_List_Builder plb; Param_List_Builder plb;
Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack prev_stack = ss.get_stack();
Dispatch_Engine::Stack new_stack; Dispatch_Engine::Stack new_stack = ss.new_stack();
unsigned int i; unsigned int i;
new_stack.push_back(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) {
@@ -452,10 +457,10 @@ namespace chaiscript
Boxed_Value retval; Boxed_Value retval;
std::vector<std::pair<std::string, Proxy_Function > > fn; std::vector<std::pair<std::string, Proxy_Function > > fn;
Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack prev_stack = ss.get_stack();
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(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
@@ -471,23 +476,32 @@ namespace chaiscript
} }
} }
std::string fun_name; //std::string fun_name;
if (node->children[i]->identifier == Token_Type::Fun_Call) { Boxed_Value fn;
fun_name = node->children[i]->children[0]->text;
}
else {
fun_name = node->children[i]->text;
}
try { try {
fn = ss.get_function(fun_name); if (node->children[i]->identifier == Token_Type::Fun_Call) {
//fun_name = node->children[i]->children[0]->text;
fn = eval_token(ss, node->children[i]->children[0]);
}
else {
//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 {
//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 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);
@@ -556,10 +570,14 @@ namespace chaiscript
template <typename Eval_System> template <typename Eval_System>
Boxed_Value eval_while(Eval_System &ss, TokenPtr node) { Boxed_Value eval_while(Eval_System &ss, TokenPtr node) {
bool cond; bool cond;
ss.new_scope();
try { try {
cond = boxed_cast<bool &>(eval_token(ss, node->children[0])); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
catch (const 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) {
@@ -569,6 +587,7 @@ namespace chaiscript
cond = boxed_cast<bool &>(eval_token(ss, node->children[0])); cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
} }
catch (const 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]);
} }
} }
@@ -576,6 +595,7 @@ namespace chaiscript
cond = false; cond = false;
} }
} }
ss.pop_scope();
return Boxed_Value(); return Boxed_Value();
} }
@@ -586,6 +606,8 @@ namespace chaiscript
Boxed_Value eval_for(Eval_System &ss, TokenPtr node) { Boxed_Value eval_for(Eval_System &ss, TokenPtr node) {
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]);
@@ -596,6 +618,7 @@ namespace chaiscript
} }
} }
catch (const 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) {
@@ -612,12 +635,14 @@ namespace chaiscript
} }
} }
catch (const 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;
} }
} }
ss.pop_scope();
return Boxed_Value(); return Boxed_Value();
} }
@@ -662,12 +687,16 @@ namespace chaiscript
param_names, _1), numparams)); param_names, _1), numparams));
} }
ss.add(Proxy_Function try {
(new 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;
} }

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

View File

@@ -13,7 +13,7 @@
#define chaiscript_prelude CODE_STRING(\ #define chaiscript_prelude CODE_STRING(\
def new(x) { eval(type_name(x))(); } \ def new(x) { eval(type_name(x))(); } \
def clone(x) { eval(type_name(x))(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() + ">"; \

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

@@ -45,6 +45,10 @@ 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; using namespace chaiscript;
@@ -59,6 +63,8 @@ int main(int argc, char *argv[]) {
chai.add(fun(&System::add_callback), "add_callback"); chai.add(fun(&System::add_callback), "add_callback");
chai.add(fun(&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
@@ -123,5 +129,8 @@ int main(int argc, char *argv[]) {
//mostly supported currently //mostly supported currently
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector")); chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
chai("dump_system()");
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
} }

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

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

View File

@@ -0,0 +1 @@
7

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