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)
target_link_libraries(chaiscript_eval ${Boost_LIBRARIES})
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
else(Boost_FOUND)
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND)

View File

@@ -87,7 +87,8 @@ namespace chaiscript
*/
struct Eval_Error : public std::runtime_error {
std::string reason;
File_Position position;
File_Position start_position;
File_Position end_position;
const char *filename;
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 ") +
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
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)
@@ -103,7 +104,7 @@ namespace chaiscript
(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), position(where->start), filename(where->filename) {
reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
}
virtual ~Eval_Error() throw() {}

View File

@@ -635,7 +635,7 @@ namespace chaiscript
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()))

View File

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

View File

@@ -97,11 +97,6 @@ namespace chaiscript
return *this;
}
static bool get_false()
{
return false;
}
Type_Info m_type_info;
boost::any m_obj;
bool m_is_ref;
@@ -116,10 +111,15 @@ namespace chaiscript
*/
struct Object_Cache
{
Object_Cache()
: m_cullcount(0)
{
}
boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return boost::shared_ptr<Data> (new Data(
Get_Type_Info<void>::get(),
detail::Get_Type_Info<void>::get(),
boost::any(),
false)
);
@@ -135,7 +135,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
boost::any(obj),
false,
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> data(new Data(
Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
boost::any(obj),
true)
);
@@ -192,7 +192,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const T& t)
{
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))),
false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
@@ -219,6 +219,12 @@ namespace chaiscript
*/
void cull()
{
++m_cullcount;
if (m_cullcount % 10 != 0)
{
return;
}
std::map<const void *, Data >::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end())
@@ -235,6 +241,7 @@ namespace chaiscript
}
std::map<const void *, Data > m_ptrs;
int m_cullcount;
};
public:
@@ -324,6 +331,8 @@ namespace chaiscript
};
namespace detail
{
// Cast_Helper helper classes
/**
@@ -472,7 +481,7 @@ namespace chaiscript
template<>
struct Cast_Helper<Boxed_Value>
{
typedef Boxed_Value Result_Type;
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
@@ -486,13 +495,14 @@ namespace chaiscript
template<>
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)
{
return ob;
}
};
}
/**
* 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);
*/
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 {
return Cast_Helper<Type>::cast(bv);
return detail::Cast_Helper<Type>::cast(bv);
} catch (const boost::bad_any_cast &) {
throw bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
@@ -669,6 +679,8 @@ namespace chaiscript
bool m_isfloat;
};
namespace detail
{
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
@@ -682,6 +694,7 @@ namespace chaiscript
return Boxed_POD_Value(ob);
}
};
}
template<typename 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)
{

View File

@@ -94,7 +94,12 @@ namespace chaiscript
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;
@@ -103,7 +108,7 @@ namespace chaiscript
while (begin != end)
{
if (begin->second->types_match(types))
if (begin->second->call_match(vals))
{
return true;
} 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
* of the object stack, functions and registered types.
@@ -133,12 +155,13 @@ namespace chaiscript
public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> Stack;
typedef boost::shared_ptr<std::deque<Scope> > Stack;
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)
{
validate_object_name(name);
return add_function(f, name);
}
@@ -163,12 +187,13 @@ namespace chaiscript
*/
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);
if (itr != m_scopes[i].end())
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
{
m_scopes[i][name] = Boxed_Value(obj);
(*m_scopes)[i][name] = Boxed_Value(obj);
return;
}
}
@@ -181,7 +206,8 @@ namespace chaiscript
*/
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()
{
m_scopes.push_back(Scope());
m_scopes->push_back(Scope());
}
/**
@@ -197,9 +223,9 @@ namespace chaiscript
*/
void pop_scope()
{
if (m_scopes.size() > 1)
if (m_scopes->size() > 1)
{
m_scopes.pop_back();
m_scopes->pop_back();
} else {
throw std::range_error("Unable to pop global stack");
}
@@ -218,10 +244,16 @@ namespace chaiscript
* \returns the old stack
* \param[in] s The new stack
*/
Stack set_stack(Stack s)
Stack set_stack(const Stack &s)
{
std::swap(s, m_scopes);
return s;
Stack old = m_scopes;
m_scopes = s;
return old;
}
Stack new_stack()
{
return Stack(new Stack::element_type());
}
/**
@@ -236,16 +268,16 @@ namespace chaiscript
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);
if (itr != m_scopes[i].end())
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
{
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())
{
@@ -312,7 +344,18 @@ namespace chaiscript
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
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,37 +366,24 @@ namespace chaiscript
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:
/**
* Implementation detail for searching for a function by name.
* Looks for all registered global functions and optionally for an object
* in scope with the same name
* Throw a reserved_word exception if the name is not allowed
*/
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
get_function_impl(const std::string &t_name, bool include_objects) const
void validate_object_name(const std::string &name)
{
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs;
if (include_objects)
if (m_reserved_words.find(name) != m_reserved_words.end())
{
try {
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 &) {
throw reserved_word_error(name);
}
}
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;
}
/**
* Implementation detail for adding a function. Returns
* true if the function was added, false if a function with the
@@ -377,11 +407,12 @@ namespace chaiscript
return true;
}
std::deque<Scope> m_scopes;
Stack m_scopes;
std::multimap<std::string, Proxy_Function > m_functions;
Type_Name_Map m_types;
Boxed_Value m_place_holder;
std::set<std::string> m_reserved_words;
};
/**

View File

@@ -4,13 +4,6 @@
// 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_hpp__
#define __function_call_hpp__
@@ -20,50 +13,7 @@
#include <string>
#include <vector>
#include "proxy_functions.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()
#include "function_call_detail.hpp"
namespace chaiscript
{
@@ -80,7 +30,7 @@ namespace chaiscript
functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
{
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

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()
{
T *f = 0;
return (build_constructor_(f));
return (detail::build_constructor_(f));
}
}
@@ -35,6 +35,8 @@ 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
@@ -57,6 +59,7 @@ namespace chaiscript
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)>))));
}
}
}
#endif

View File

@@ -4,109 +4,22 @@
// and Jason Turner (lefticus@gmail.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__
#define __proxy_functions_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
#include "proxy_functions_detail.hpp"
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
* it does automatic conversion to Boxed_Value types via operator<<
@@ -138,30 +51,6 @@ namespace chaiscript
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
* 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 std::vector<Type_Info> get_param_types() 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;
};
@@ -209,7 +139,8 @@ namespace chaiscript
int t_arity=-1,
const std::string &t_description = "",
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;
}
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))
&& test_guard(types);
return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals);
}
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
{
std::vector<Type_Info> 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;
return m_types;
}
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;
int m_arity;
std::string m_description;
Proxy_Function m_guard;
std::vector<Type_Info> m_types;
};
/**
@@ -309,7 +251,7 @@ namespace chaiscript
public:
Bound_Function(const Proxy_Function &t_f,
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 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->types_match(params);
return m_f->call_match(build_param_list(vals));
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
@@ -343,7 +284,7 @@ namespace chaiscript
while (true)
{
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);
++barg;
@@ -356,7 +297,7 @@ namespace chaiscript
}
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;
}
@@ -374,6 +315,11 @@ namespace chaiscript
return std::vector<Type_Info>();
}
virtual int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const
{
return "";
@@ -382,6 +328,7 @@ namespace chaiscript
private:
Proxy_Function m_f;
std::vector<Boxed_Value> m_args;
int m_arity;
};
/**
@@ -394,7 +341,7 @@ namespace chaiscript
{
public:
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
{
Func *f = 0;
return build_param_type_list(f);
return m_types;
}
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual int get_arity() const
{
Func *f = 0;
return compare_types(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
@@ -434,6 +385,8 @@ namespace chaiscript
private:
boost::function<Func> m_f;
Func *m_dummy_func;
std::vector<Type_Info> m_types;
};
/**
@@ -465,7 +418,10 @@ namespace chaiscript
++itr)
{
try {
if (itr->second->filter(plist))
{
return (*itr->second)(plist);
}
} catch (const bad_boxed_cast &) {
//parameter failed to cast, try again
} 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

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,13 +16,8 @@
namespace chaiscript
{
template<typename T>
Proxy_Function fun(const boost::function<T> &f)
namespace detail
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
/**
* Helper function for register_member function
*/
@@ -32,54 +27,74 @@ namespace chaiscript
return (obj->*m);
}
template<typename T>
Proxy_Function fun_helper(const boost::function<T> &f)
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
/**
* 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)
Proxy_Function fun_helper(T Class::* m)
{
return fun(boost::function<T& (Class *)>(boost::bind(&get_member<T, Class>, m, _1)));
return fun_helper(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
}
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp>
#include BOOST_PP_ITERATE()
namespace chaiscript
{
template<typename T>
Proxy_Function fun(T t)
{
return detail::fun_helper(t);
}
}
# endif
#else
# define n BOOST_PP_ITERATION()
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)>
Proxy_Function fun(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
Proxy_Function fun_helper(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
return fun(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f));
return fun_helper(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f));
}
/**
* 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)>
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
*/
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));
}
}
}

View File

@@ -77,6 +77,8 @@ namespace chaiscript
bool m_is_unknown;
};
namespace detail
{
/**
* Helper used to create a Type_Info object
*/
@@ -104,6 +106,18 @@ namespace chaiscript
}
};
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>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
@@ -115,19 +129,19 @@ namespace chaiscript
&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 Get_Type_Info<T>::get();
return detail::Get_Type_Info<T>::get();
}
template<typename T>
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>
class ChaiScript_System {
Eval_Engine engine;
std::set<std::string> loaded_files;
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 char *filename = "__EVAL__") {
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, filename)) {
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
@@ -49,6 +58,14 @@ namespace chaiscript
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:
ChaiScript_System() {
@@ -117,12 +134,11 @@ namespace chaiscript
/**
* Helper function for loading a file
*/
std::string load_file(const char *filename) {
std::ifstream infile (filename, std::ios::in | std::ios::ate);
std::string load_file(const std::string &filename) {
std::ifstream infile (filename.c_str(), std::ios::in | std::ios::ate);
if (!infile.is_open()) {
std::string fname = filename;
throw std::runtime_error("Can not open: " + fname);
throw std::runtime_error("Can not open: " + filename);
}
std::streampos size = infile.tellg();
@@ -141,6 +157,24 @@ namespace chaiscript
*/
void build_eval_system() {
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(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))),
"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");
@@ -176,7 +214,7 @@ namespace chaiscript
/**
* 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);
}
@@ -184,7 +222,7 @@ namespace chaiscript
* Loads the file specified by filename, evaluates it, and returns the as the specified type
*/
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));
}
};

View File

@@ -171,7 +171,12 @@ namespace chaiscript
*/
template <typename Eval_System>
Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) {
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);
}
@@ -405,10 +410,10 @@ namespace chaiscript
Boxed_Value retval;
Param_List_Builder plb;
Dispatch_Engine::Stack prev_stack = ss.get_stack();
Dispatch_Engine::Stack new_stack;
Dispatch_Engine::Stack new_stack = ss.new_stack();
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)) {
for (i = 0; i < node->children[1]->children.size(); ++i) {
@@ -452,10 +457,10 @@ namespace chaiscript
Boxed_Value retval;
std::vector<std::pair<std::string, Proxy_Function > > fn;
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;
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
@@ -471,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) {
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 {
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 {
fn = ss.get_function(fun_name);
//fn = ss.get_function(fun_name);
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);
}
catch(const dispatch_error &e){
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) {
ss.set_stack(prev_stack);
@@ -556,10 +570,14 @@ namespace chaiscript
template <typename Eval_System>
Boxed_Value eval_while(Eval_System &ss, TokenPtr node) {
bool cond;
ss.new_scope();
try {
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
}
catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("While condition not boolean", node->children[0]);
}
while (cond) {
@@ -569,6 +587,7 @@ namespace chaiscript
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
}
catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("While condition not boolean", node->children[0]);
}
}
@@ -576,6 +595,7 @@ namespace chaiscript
cond = false;
}
}
ss.pop_scope();
return Boxed_Value();
}
@@ -586,6 +606,8 @@ namespace chaiscript
Boxed_Value eval_for(Eval_System &ss, TokenPtr node) {
bool cond;
ss.new_scope();
try {
if (node->children.size() == 4) {
eval_token(ss, node->children[0]);
@@ -596,6 +618,7 @@ namespace chaiscript
}
}
catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("For condition not boolean", node);
}
while (cond) {
@@ -612,12 +635,14 @@ namespace chaiscript
}
}
catch (const bad_boxed_cast &) {
ss.pop_scope();
throw Eval_Error("For condition not boolean", node);
}
catch (Break_Loop &) {
cond = false;
}
}
ss.pop_scope();
return Boxed_Value();
}
@@ -662,12 +687,16 @@ namespace chaiscript
param_names, _1), numparams));
}
try {
ss.add(Proxy_Function
(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
boost::ref(ss), node->children.back(),
param_names, _1), numparams,
annotation, guard)), function_name);
}
catch (reserved_word_error &rwe) {
throw Eval_Error("Reserved word used as function name '" + function_name + "'", node);
}
return retval;
}

View File

@@ -140,7 +140,7 @@ namespace chaiscript
*/
bool Float_() {
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')) {
++input_pos;
++col;
@@ -178,7 +178,7 @@ namespace chaiscript
std::string::iterator start = input_pos;
int prev_col = col;
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_()) {
std::string match(start, input_pos);
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(\
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\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \

View File

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

View File

@@ -2,7 +2,7 @@ var i = 0
if (i == 0) {
print("i is 0")
}
elseif (i == 1) {
else if (i == 1) {
print("i is 1")
}
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[]) {
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::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.
// 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
@@ -123,5 +129,8 @@ int main(int argc, char *argv[]) {
//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\");");
}

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