diff --git a/Doxyfile.in b/Doxyfile.in index 57d35f4c..064d54f7 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1357,7 +1357,7 @@ PERLMOD_MAKEVAR_PREFIX = # evaluate all C-preprocessor directives found in the sources and include # files. -ENABLE_PREPROCESSING = YES +ENABLE_PREPROCESSING = NO # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 4cf40887..da1e4e5d 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -1,21 +1,34 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_ -#include -#include -#include -#include -#include -#include -#include -#include + +/// \mainpage +/// ChaiScript is a scripting language designed specifically for integration with C++. It provides +/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions. +/// +/// The parts of the ChaiScript API that the average user will be concerned with are contained in the +/// chaiscript namespace and the chaiscript::ChaiScript class. +/// +/// The end user parts of the API are extremely simple both in size and ease of use. +/// +/// Currently, all source control and project management aspects of ChaiScript occur on github. +/// +/// \sa chaiscript +/// \sa chaiscript::ChaiScript +/// \sa http://www.chaiscript.com +/// \sa http://www.github.com/ChaiScript/ChaiScript + + +/// \namespace chaiscript +/// The chaiscript namespace contains every API call that the average user will be concerned with. + #include "dispatchkit/dispatchkit.hpp" #include "dispatchkit/bootstrap.hpp" diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index cebb40f7..10d9df23 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -1,3 +1,9 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) +// and Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + #ifndef CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_ @@ -7,15 +13,34 @@ #pragma message ("ChaiScript is compiling without thread safety.") #endif +/// \file +/// +/// This file contains code necessary for thread support in ChaiScript. +/// If the compiler definition CHAISCRIPT_NO_THREADS is defined then thread safety +/// is disabled in ChaiScript. This has the result that some code is faster, because mutex locks are not required. +/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than +/// one thread simultaneously. + namespace chaiscript { namespace detail { + /// If threading is enabled, then this namespace contains boost::thread classes. + /// If threading is not enabled, then stubbed in wrappers that do nothing are provided. + /// This allows us to avoid #ifdef code in the sections that need thread safety. namespace threading { #ifndef CHAISCRIPT_NO_THREADS + using boost::unique_lock; + using boost::shared_lock; + using boost::lock_guard; + using boost::shared_mutex; + using boost::recursive_mutex; + + /// Typesafe thread specific storage. If threading is enabled, this class uses boost::thread_specific_ptr. If + /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. template class Thread_Storage { @@ -45,6 +70,32 @@ namespace chaiscript }; #else + template + class unique_lock + { + public: + unique_lock(T &) {} + }; + + template + class shared_lock + { + public: + shared_lock(T &) {} + void unlock() {} + }; + + template + class lock_guard + { + public: + lock_guard(T &) {} + }; + + class shared_mutex { }; + + class recursive_mutex {}; + template class Thread_Storage diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 1070ecdb..ef26d0b3 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -13,10 +13,11 @@ namespace chaiscript { namespace exception { - /** - * class that is thrown in the event of a bad_boxed_cast. That is, - * in the case that a Boxed_Value cannot be cast to the desired type - */ + /// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type + /// + /// It is used internally during function dispatch and may be used by the end user. + /// + /// \sa chaiscript::boxed_cast class bad_boxed_cast : public std::bad_cast { public: @@ -38,13 +39,14 @@ namespace chaiscript virtual ~bad_boxed_cast() throw() {} + /// \brief Description of what error occured virtual const char * what() const throw() { return m_what.c_str(); } - Type_Info from; - const std::type_info *to; + Type_Info from; ///< Type_Info contained in the Boxed_Value + const std::type_info *to; ///< std::type_info of the desired (but failed) result type private: std::string m_what; diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 7c0a338c..ae468f1a 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -30,9 +30,14 @@ namespace chaiscript { - namespace detail { + /// \brief Helper function for binding the first parameter of a class method pointer. Used in chaiscript::fun overloads + /// that take 1 or 2 parameters to pre-bind to the function. + /// + /// \param[in] f method pointer to bind + /// \param[in] o object to bind as first parameter + /// \returns a new boost::function object with one fewer parameters than the function passed in. template boost::function bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const O &o) @@ -40,13 +45,25 @@ namespace chaiscript return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _)); } + /// \brief Helper function for binding the first parameter of a const class method pointer. Used in chaiscript::fun overloads + /// that take 1 or 2 parameters to pre-bind to the function. + /// + /// \param[in] f method pointer to bind + /// \param[in] o object to bind as first parameter + /// \returns a new boost::function object with one fewer parameters than the function passed in. template boost::function - bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const O &o) + bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)) const, const O &o) { return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _)); } + /// \brief Helper function for binding the first parameter of a function pointer. Used in chaiscript::fun overloads + /// that take 1 or 2 parameters to pre-bind to the function. + /// + /// \param[in] f method pointer to bind + /// \param[in] o object to bind as first parameter + /// \returns a new boost::function object with one fewer parameters than the function passed in. template boost::function bind_first(Ret (*f)(BOOST_PP_ENUM_PARAMS(m, Param)), const O &o) @@ -54,6 +71,12 @@ namespace chaiscript return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _)); } + /// \brief Helper function for binding the first parameter of a boost::function object. Used in chaiscript::fun overloads + /// that take 1 or 2 parameters to pre-bind to the function. + /// + /// \param[in] f method pointer to bind + /// \param[in] o object to bind as first parameter + /// \returns a new boost::function object with one fewer parameters than the function passed in. template boost::function bind_first(const boost::function &f, const O &o) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index ceb84413..529ca023 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -21,17 +21,15 @@ namespace chaiscript namespace detail { - /* Special helpers for generating generic "POD" type operators - * The POD operators are needed for general support of C++ POD - * types without iterating out all possible combinations of operators - * (<, >, +, +=, *=, \=, -, <=, >=, ==) and types - * (char, uint8_t, int8_t, uint16_t, int16_t...) - */ + /// \brief Assigns a POD value from a Boxed_POD_Value. Helps support operators between + /// disparate POD types. + /// \param[in,out] p1 object to assign to + /// \param[in] v Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template - P1 &assign_pod(P1 &p1, Boxed_POD_Value v) + P1 &assign_pod(P1 &p1, const Boxed_POD_Value &v) { - - if (v.m_isfloat) + if (v.isfloat) { return (p1 = P1(v.d)); } else { @@ -39,10 +37,13 @@ namespace chaiscript } } + /// \brief Constructs a new POD value object from a Boxed_POD_Value + /// \param[in] v Boxed_POD_Value to copy into the new object + /// \returns The newly created object. template P1 construct_pod(Boxed_POD_Value v) { - if (v.m_isfloat) + if (v.isfloat) { return P1(v.d); } else { @@ -50,10 +51,14 @@ namespace chaiscript } } + /// \brief Performs a bitwise and assignment (&=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to bitwise and assign to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 &= P1(r.i); } @@ -61,10 +66,14 @@ namespace chaiscript throw exception::bad_boxed_cast("&= only valid for integer types"); } + /// \brief Performs a xor assignment (^=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to xor assign to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 ^= P1(r.i); } @@ -72,10 +81,14 @@ namespace chaiscript throw exception::bad_boxed_cast("^= only valid for integer types"); } + /// \brief Performs a bitwise or assignment (|=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to bitwise or assign to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 |= P1(r.i); } @@ -83,10 +96,14 @@ namespace chaiscript throw exception::bad_boxed_cast("&= only valid for integer types"); } + /// \brief Performs an assign difference (-=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to difference assign to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 -= P1(r.d); } else { @@ -94,10 +111,14 @@ namespace chaiscript } } + /// \brief Performs an assign shift left (<<=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to assign shift left to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 <<= P1(r.i); } @@ -106,10 +127,14 @@ namespace chaiscript } + /// \brief Performs an assign product (*=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to assign product to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 *= P1(r.d); } else { @@ -117,10 +142,14 @@ namespace chaiscript } } + /// \brief Performs an assign quotient (/=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to assign quotient to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 /= P1(r.d); } else { @@ -128,10 +157,14 @@ namespace chaiscript } } + /// \brief Performs an assign remainder (%=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to assign remainder to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 %= P1(r.i); } @@ -140,10 +173,14 @@ namespace chaiscript } + /// \brief Performs an assign shift right (>>=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to assign shift right to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 >>= P1(r.i); } @@ -151,11 +188,14 @@ namespace chaiscript throw exception::bad_boxed_cast(">>= only valid for integer types"); } - + /// \brief Performs an assign sum (+=) on the given object with the given Boxed_POD_Value + /// \param[in,out] p1 object to sum assign to + /// \param[in] r Boxed_POD_Value to assign from + /// \returns Reference to p1, to support normal C assignment semantics template P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 += P1(r.d); } else { @@ -165,6 +205,10 @@ namespace chaiscript } + /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. + /// \tparam T Type to create comparison operators for + /// \param[in,out] m module to add comparison operators to + /// \returns the passed in ModulePtr or the newly constructed one if the default params are used. template ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module())) { @@ -177,6 +221,12 @@ namespace chaiscript return m; } + + /// \brief Add all arithmetic operators appropriate for integers for the templated type. + /// Used during bootstrap, also available to users. + /// \tparam T Type to create arithmetic operators for + /// \param[in,out] m module to add arithmetic operators to + /// \returns the passed in ModulePtr or the newly constructed one if the default params are used. template ModulePtr opers_integer_arithmetic(ModulePtr m = ModulePtr(new Module())) { @@ -209,6 +259,11 @@ namespace chaiscript return m; } + /// \brief Add all arithmetic operators appropriate for floating point numbers for the templated type. + /// Used during bootstrap, also available to users. + /// \tparam T Type to create arithmetic operators for + /// \param[in,out] m module to add arithmetic operators to + /// \returns the passed in ModulePtr or the newly constructed one if the default params are used. template ModulePtr opers_float_arithmetic(ModulePtr m = ModulePtr(new Module())) { @@ -226,9 +281,11 @@ namespace chaiscript return m; } - /** - * Add a copy constructor for type T - */ + /// \brief Adds a copy constructor for the given type to the given Model + /// \param[in] type The name of the type. The copy constructor will be named "type". + /// \param[in,out] m The Module to add the copy constructor to + /// \tparam T The type to add a copy constructor for + /// \returns The passed in ModulePtr, or the newly constructed one if the default param is used template ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module())) { @@ -236,9 +293,13 @@ namespace chaiscript return m; } - /** - * Add default and copy constructors for type T - */ + /// \brief Adds default and copy constructors for the given type + /// \param[in] type The name of the type to add the constructors for. + /// \param[in,out] m The Module to add the basic constructors to + /// \tparam T Type to generate basic constructors for + /// \returns The passed in ModulePtr, or the newly constructed one if the default param is used + /// \sa copy_constructor + /// \sa constructor template ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module())) { @@ -247,9 +308,10 @@ namespace chaiscript return m; } - /** - * Add POD type constructor for type T. ie: T = type(POD) - */ + /// \brief Adds a constructor for a POD type + /// \tparam T The type to add the constructor for + /// \param[in] T The name of the type + /// \param[in,out] m The Module to add the constructor to template ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module())) { @@ -257,16 +319,6 @@ namespace chaiscript return m; } - /** - * add user defined single parameter constructor for type T. - * T = type(const U &) - */ - template - ModulePtr constructor_overload(const std::string &type, ModulePtr m = ModulePtr(new Module())) - { - m->add(constructor(), type); - return m; - } /** * to_string function for internal use. Uses ostream operator<< @@ -458,7 +510,7 @@ namespace chaiscript Const_Proxy_Function f = boxed_cast(params[0]); - return Boxed_Value(Const_Proxy_Function(new Bound_Function(f, + return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f, std::vector(params.begin() + 1, params.end())))); } @@ -480,7 +532,7 @@ namespace chaiscript static bool has_guard(const Const_Proxy_Function &t_pf) { - boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); if (pf) { return pf->get_guard(); @@ -491,7 +543,7 @@ namespace chaiscript static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) { - boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); if (pf) { if (pf->get_guard()) @@ -509,7 +561,7 @@ namespace chaiscript throw bv; } - static boost::shared_ptr bootstrap2(boost::shared_ptr e = boost::shared_ptr (new Dispatch_Engine())) + static boost::shared_ptr bootstrap2(boost::shared_ptr e = boost::shared_ptr (new chaiscript::detail::Dispatch_Engine())) { e->add(user_type(), "void"); return e; @@ -535,7 +587,7 @@ namespace chaiscript template static std::vector do_return_boxed_value_vector(FunctionType f, - const Proxy_Function_Base *b) + const dispatch::Proxy_Function_Base *b) { typedef typename boost::function_types::result_type::type Vector; Vector v = (b->*f)(); @@ -552,15 +604,15 @@ namespace chaiscript } template - static boost::function (const Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) + static boost::function (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) { return boost::bind(&do_return_boxed_value_vector, f, _1); } public: - /** - * perform all common bootstrap functions for std::string, void and POD types - */ + /// \brief perform all common bootstrap functions for std::string, void and POD types + /// \param[in,out] m Module to add bootstrapped functions to + /// \returns passed in ModulePtr, or newly created one if default argument is used static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module())) { m->add(user_type(), "void"); @@ -570,14 +622,14 @@ namespace chaiscript m->add(user_type(), "function"); m->add(user_type(), "exception"); - m->add(fun(&Proxy_Function_Base::get_arity), "get_arity"); - m->add(fun(&Proxy_Function_Base::annotation), "get_annotation"); - m->add(fun(&Proxy_Function_Base::operator()), "call"); - m->add(fun(&Proxy_Function_Base::operator==), "=="); + m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); + m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); + m->add(fun(&dispatch::Proxy_Function_Base::operator()), "call"); + m->add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); - m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_param_types)), "get_param_types"); - m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); + m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); + m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m->add(user_type(), "runtime_error"); @@ -587,11 +639,11 @@ namespace chaiscript m->add(constructor(), "runtime_error"); m->add(fun(boost::function(&what)), "what"); - m->add(user_type(), "Dynamic_Object"); - m->add(constructor(), "Dynamic_Object"); - m->add(fun(&Dynamic_Object::get_type_name), "get_type_name"); - m->add(fun(&Dynamic_Object::get_attrs), "get_attrs"); - m->add(fun(&Dynamic_Object::get_attr), "get_attr"); + m->add(user_type(), "Dynamic_Object"); + m->add(constructor(), "Dynamic_Object"); + m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name"); + m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs"); + m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr"); m->eval("def Dynamic_Object::clone() { var new_o := Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }"); @@ -648,14 +700,14 @@ namespace chaiscript m->add(fun(&print), "print_string"); m->add(fun(&println), "println_string"); - m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))), + m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&bind_function, _1))), "bind"); - m->add(fun(&shared_ptr_unconst_clone), "clone"); - m->add(fun(&ptr_assign::type>), "="); - m->add(fun(&ptr_assign::type>), "="); + m->add(fun(&shared_ptr_unconst_clone), "clone"); + m->add(fun(&ptr_assign::type>), "="); + m->add(fun(&ptr_assign::type>), "="); - m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))), + m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&call_exists, _1))), "call_exists"); m->add(fun(&type_match), "type_match"); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 82b9ba5f..96710c09 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -1,14 +1,17 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com /** -* This file contains utility functions for registration of STL container -* classes. The methodology used is based on the SGI STL concepts. -* http://www.sgi.com/tech/stl/table_of_contents.html -*/ + * \file + * This file contains utility functions for registration of STL container + * classes. The methodology used is based on the SGI STL concepts. + * http://www.sgi.com/tech/stl/table_of_contents.html + */ + + #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 6cd137c3..242771b6 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -49,7 +49,7 @@ namespace chaiscript try { // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return detail::Cast_Helper::cast(boxed_dynamic_cast(bv)); + return detail::Cast_Helper::cast(detail::boxed_dynamic_cast(bv)); } catch (const boost::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 53a60793..ceb01780 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com diff --git a/include/chaiscript/dispatchkit/boxed_pod_value.hpp b/include/chaiscript/dispatchkit/boxed_pod_value.hpp index 47458b00..57b52669 100644 --- a/include/chaiscript/dispatchkit/boxed_pod_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_pod_value.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -21,205 +21,205 @@ namespace chaiscript * Object which attempts to convert a Boxed_Value into a generic * POD type and provide generic POD type operations */ - struct Boxed_POD_Value + class Boxed_POD_Value { - Boxed_POD_Value(const Boxed_Value &v) - : d(0), i(0), m_isfloat(false) - { - if (v.get_type_info().is_undef()) + public: + Boxed_POD_Value(const Boxed_Value &v) + : d(0), i(0), isfloat(false) { - throw boost::bad_any_cast(); + if (v.get_type_info().is_undef()) + { + throw boost::bad_any_cast(); + } + + const Type_Info &inp_ = v.get_type_info(); + + if (inp_ == typeid(double)) + { + d = boxed_cast(v); + isfloat = true; + } else if (inp_ == typeid(float)) { + d = boxed_cast(v); + isfloat = true; + } else if (inp_ == typeid(bool)) { + i = boxed_cast(v); + } else if (inp_ == typeid(char)) { + i = boxed_cast(v); + } else if (inp_ == typeid(int)) { + i = boxed_cast(v); + } else if (inp_ == typeid(unsigned int)) { + i = boxed_cast(v); + } else if (inp_ == typeid(long)) { + i = boxed_cast(v); + } else if (inp_ == typeid(unsigned long)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int8_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int16_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int32_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int64_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint8_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint16_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint32_t)) { + i = boxed_cast(v); + } else { + throw boost::bad_any_cast(); + } } - const Type_Info &inp_ = v.get_type_info(); - - if (inp_ == typeid(double)) + bool operator==(const Boxed_POD_Value &r) const { - d = boxed_cast(v); - m_isfloat = true; - } else if (inp_ == typeid(float)) { - d = boxed_cast(v); - m_isfloat = true; - } else if (inp_ == typeid(bool)) { - i = boxed_cast(v); - } else if (inp_ == typeid(char)) { - i = boxed_cast(v); - } else if (inp_ == typeid(int)) { - i = boxed_cast(v); - } else if (inp_ == typeid(unsigned int)) { - i = boxed_cast(v); - } else if (inp_ == typeid(long)) { - i = boxed_cast(v); - } else if (inp_ == typeid(unsigned long)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int8_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int16_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int32_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int64_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint8_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint16_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint32_t)) { - i = boxed_cast(v); - } else { - throw boost::bad_any_cast(); - } - } - - bool operator==(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) == ((r.m_isfloat)?r.d:r.i); - } - - bool operator<(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) < ((r.m_isfloat)?r.d:r.i); - } - - bool operator>(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) > ((r.m_isfloat)?r.d:r.i); - } - - bool operator>=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) >= ((r.m_isfloat)?r.d:r.i); - } - - bool operator<=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) <= ((r.m_isfloat)?r.d:r.i); - } - - bool operator!=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) != ((r.m_isfloat)?r.d:r.i); - } - - Boxed_Value operator+(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i + r.i); + return ((isfloat)?d:i) == ((r.isfloat)?r.d:r.i); } - return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator-(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + bool operator<(const Boxed_POD_Value &r) const { - return smart_size(i - r.i); + return ((isfloat)?d:i) < ((r.isfloat)?r.d:r.i); } - return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator&(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + bool operator>(const Boxed_POD_Value &r) const { - return Boxed_Value(i & r.i); + return ((isfloat)?d:i) > ((r.isfloat)?r.d:r.i); } - throw exception::bad_boxed_cast("& only valid for integer types"); - } - - Boxed_Value operator^(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + bool operator>=(const Boxed_POD_Value &r) const { - return Boxed_Value(i ^ r.i); + return ((isfloat)?d:i) >= ((r.isfloat)?r.d:r.i); } - throw exception::bad_boxed_cast("^ only valid for integer types"); - } - - Boxed_Value operator|(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + bool operator<=(const Boxed_POD_Value &r) const { - return Boxed_Value(i | r.i); + return ((isfloat)?d:i) <= ((r.isfloat)?r.d:r.i); } - throw exception::bad_boxed_cast("| only valid for integer types"); - } - - Boxed_Value operator/(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + bool operator!=(const Boxed_POD_Value &r) const { - return smart_size(i / r.i); + return ((isfloat)?d:i) != ((r.isfloat)?r.d:r.i); } - return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator<<(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + Boxed_Value operator+(const Boxed_POD_Value &r) const { - return smart_size(i << r.i); + if (!isfloat && !r.isfloat) + { + return smart_size(i + r.i); + } + + return Boxed_Value(((isfloat)?d:i) + ((r.isfloat)?r.d:r.i)); } - throw exception::bad_boxed_cast("<< only valid for integer types"); - } - - - Boxed_Value operator*(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + Boxed_Value operator-(const Boxed_POD_Value &r) const { - return smart_size(i * r.i); + if (!isfloat && !r.isfloat) + { + return smart_size(i - r.i); + } + + return Boxed_Value(((isfloat)?d:i) - ((r.isfloat)?r.d:r.i)); } - return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i)); - } - - - Boxed_Value operator%(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + Boxed_Value operator&(const Boxed_POD_Value &r) const { - return smart_size(i % r.i); + if (!isfloat && !r.isfloat) + { + return Boxed_Value(i & r.i); + } + + throw exception::bad_boxed_cast("& only valid for integer types"); } - throw exception::bad_boxed_cast("% only valid for integer types"); - } - - Boxed_Value operator>>(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) + Boxed_Value operator^(const Boxed_POD_Value &r) const { - return smart_size(i >> r.i); + if (!isfloat && !r.isfloat) + { + return Boxed_Value(i ^ r.i); + } + + throw exception::bad_boxed_cast("^ only valid for integer types"); } - throw exception::bad_boxed_cast(">> only valid for integer types"); - } - - Boxed_Value smart_size(boost::int64_t t_i) const - { - if (t_i < boost::integer_traits::const_min - || t_i > boost::integer_traits::const_max) + Boxed_Value operator|(const Boxed_POD_Value &r) const { - return Boxed_Value(t_i); - } else { - return Boxed_Value(static_cast(t_i)); + if (!isfloat && !r.isfloat) + { + return Boxed_Value(i | r.i); + } + + throw exception::bad_boxed_cast("| only valid for integer types"); + } + + Boxed_Value operator/(const Boxed_POD_Value &r) const + { + if (!isfloat && !r.isfloat) + { + return smart_size(i / r.i); + } + + return Boxed_Value(((isfloat)?d:i) / ((r.isfloat)?r.d:r.i)); + } + + Boxed_Value operator<<(const Boxed_POD_Value &r) const + { + if (!isfloat && !r.isfloat) + { + return smart_size(i << r.i); + } + + throw exception::bad_boxed_cast("<< only valid for integer types"); } - } + Boxed_Value operator*(const Boxed_POD_Value &r) const + { + if (!isfloat && !r.isfloat) + { + return smart_size(i * r.i); + } - double d; - boost::int64_t i; + return Boxed_Value(((isfloat)?d:i) * ((r.isfloat)?r.d:r.i)); + } - bool m_isfloat; + + Boxed_Value operator%(const Boxed_POD_Value &r) const + { + if (!isfloat && !r.isfloat) + { + return smart_size(i % r.i); + } + + throw exception::bad_boxed_cast("% only valid for integer types"); + } + + Boxed_Value operator>>(const Boxed_POD_Value &r) const + { + if (!isfloat && !r.isfloat) + { + return smart_size(i >> r.i); + } + + throw exception::bad_boxed_cast(">> only valid for integer types"); + } + + Boxed_Value smart_size(boost::int64_t t_i) const + { + if (t_i < boost::integer_traits::const_min + || t_i > boost::integer_traits::const_max) + { + return Boxed_Value(t_i); + } else { + return Boxed_Value(static_cast(t_i)); + } + } + + + double d; + boost::int64_t i; + + bool isfloat; }; namespace detail diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index f71f4f24..490f9c80 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 9b0b304b..94d22f0f 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -111,574 +111,570 @@ namespace chaiscript typedef boost::shared_ptr ModulePtr; - /** - * A Proxy_Function implementation that is able to take - * a vector of Proxy_Functions and perform a dispatch on them. It is - * used specifically in the case of dealing with Function object variables - */ - class Dispatch_Function : public Proxy_Function_Base + namespace detail { - public: - Dispatch_Function(const std::vector &t_funcs) - : Proxy_Function_Base(build_type_infos(t_funcs)), + /** + * A Proxy_Function implementation that is able to take + * a vector of Proxy_Functions and perform a dispatch on them. It is + * used specifically in the case of dealing with Function object variables + */ + class Dispatch_Function : public dispatch::Proxy_Function_Base + { + public: + Dispatch_Function(const std::vector &t_funcs) + : Proxy_Function_Base(build_type_infos(t_funcs)), m_funcs(t_funcs) { } - virtual bool operator==(const Proxy_Function_Base &rhs) const - { - try { - const Dispatch_Function &dispatchfun = dynamic_cast(rhs); - return m_funcs == dispatchfun.m_funcs; - } catch (const std::bad_cast &) { + virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const + { + try { + const Dispatch_Function &dispatchfun = dynamic_cast(rhs); + return m_funcs == dispatchfun.m_funcs; + } catch (const std::bad_cast &) { + return false; + } + } + + virtual ~Dispatch_Function() {} + + virtual std::vector get_contained_functions() const + { + return std::vector(m_funcs.begin(), m_funcs.end()); + } + + + virtual int get_arity() const + { + typedef std::vector function_vec; + + function_vec::const_iterator begin = m_funcs.begin(); + const function_vec::const_iterator end = m_funcs.end(); + + if (begin != end) + { + int arity = (*begin)->get_arity(); + + ++begin; + + while (begin != end) + { + if (arity != (*begin)->get_arity()) + { + // The arities in the list do not match, so it's unspecified + return -1; + } + + ++begin; + } + + return arity; + } + + return -1; // unknown arity + } + + virtual bool call_match(const std::vector &vals) const + { + typedef std::vector function_vec; + + function_vec::const_iterator begin = m_funcs.begin(); + function_vec::const_iterator end = m_funcs.end(); + + while (begin != end) + { + if ((*begin)->call_match(vals)) + { + return true; + } else { + ++begin; + } + } + return false; } - } - virtual ~Dispatch_Function() {} - - virtual std::vector get_contained_functions() const - { - return std::vector(m_funcs.begin(), m_funcs.end()); - } - - - virtual int get_arity() const - { - typedef std::vector function_vec; - - function_vec::const_iterator begin = m_funcs.begin(); - const function_vec::const_iterator end = m_funcs.end(); - - if (begin != end) + virtual std::string annotation() const { - int arity = (*begin)->get_arity(); - - ++begin; - - while (begin != end) - { - if (arity != (*begin)->get_arity()) - { - // The arities in the list do not match, so it's unspecified - return -1; - } - - ++begin; - } - - return arity; + return "Multiple method dispatch function wrapper."; } - return -1; // unknown arity - } - - virtual bool call_match(const std::vector &vals) const - { - typedef std::vector function_vec; - - function_vec::const_iterator begin = m_funcs.begin(); - function_vec::const_iterator end = m_funcs.end(); - - while (begin != end) + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const { - if ((*begin)->call_match(vals)) - { - return true; - } else { - ++begin; - } + return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params); } - return false; - } + private: + std::vector m_funcs; - virtual std::string annotation() const - { - return "Multiple method dispatch function wrapper."; - } - - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - return dispatch(m_funcs.begin(), m_funcs.end(), params); - } - - private: - std::vector m_funcs; - - static std::vector build_type_infos(const std::vector &t_funcs) - { - typedef std::vector function_vec; - - function_vec::const_iterator begin = t_funcs.begin(); - const function_vec::const_iterator end = t_funcs.end(); - - if (begin != end) + static std::vector build_type_infos(const std::vector &t_funcs) { - std::vector type_infos = (*begin)->get_param_types(); + typedef std::vector function_vec; - ++begin; + function_vec::const_iterator begin = t_funcs.begin(); + const function_vec::const_iterator end = t_funcs.end(); - bool sizemismatch = false; - - while (begin != end) + if (begin != end) { - std::vector param_types = (*begin)->get_param_types(); + std::vector type_infos = (*begin)->get_param_types(); - if (param_types.size() != type_infos.size()) - { - sizemismatch = true; - } + ++begin; - for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i) + bool sizemismatch = false; + + while (begin != end) { - if (!(type_infos[i] == param_types[i])) + std::vector param_types = (*begin)->get_param_types(); + + if (param_types.size() != type_infos.size()) { - type_infos[i] = detail::Get_Type_Info::get(); + sizemismatch = true; } + + for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i) + { + if (!(type_infos[i] == param_types[i])) + { + type_infos[i] = detail::Get_Type_Info::get(); + } + } + + ++begin; } - ++begin; + assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); + + if (sizemismatch) + { + type_infos.resize(1); + } + + return type_infos; } - assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); - - if (sizemismatch) - { - type_infos.resize(1); - } - - return type_infos; + return std::vector(); } + }; + } - return std::vector(); - } - }; - - - /** - * 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 + namespace exception { - reserved_word_error(const std::string &t_word) throw() - : std::runtime_error("Reserved word not allowed in object name: " + word), word(t_word) + /** + * 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 + */ + class reserved_word_error : public std::runtime_error { - } + public: + reserved_word_error(const std::string &t_word) throw() + : std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word) + { + } - std::string word; + virtual ~reserved_word_error() throw() {} - virtual ~reserved_word_error() throw() {} - }; + std::string word() const + { + return m_word; + } - /** - * Exception thrown in the case that a non-const object was added as a shared object - */ - struct global_non_const : std::runtime_error - { - global_non_const() throw() - : std::runtime_error("a global object must be const") + private: + std::string m_word; + + }; + + /** + * Exception thrown in the case that a non-const object was added as a shared object + */ + class global_non_const : public std::runtime_error { - } + public: + global_non_const() throw() + : std::runtime_error("a global object must be const") + { + } - virtual ~global_non_const() throw() {} - }; + virtual ~global_non_const() throw() {} + }; + } - - /** - * Main class for the dispatchkit. Handles management - * of the object stack, functions and registered types. - */ - class Dispatch_Engine + namespace detail { - public: - typedef std::map Type_Name_Map; - typedef std::map Scope; - typedef std::deque StackData; - typedef boost::shared_ptr Stack; + /** + * Main class for the dispatchkit. Handles management + * of the object stack, functions and registered types. + */ + class Dispatch_Engine + { + public: + typedef std::map Type_Name_Map; + typedef std::map Scope; + typedef std::deque StackData; + typedef boost::shared_ptr Stack; - struct State - { - std::map > m_functions; - std::map m_global_objects; - Type_Name_Map m_types; - std::set m_reserved_words; - }; - - Dispatch_Engine() - : m_place_holder(boost::shared_ptr(new Placeholder_Object())) - { - } - - ~Dispatch_Engine() - { - detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end()); - } - - /** - * Add a new conversion for upcasting to a base class - */ - void add(const Dynamic_Cast_Conversion &d) - { - m_conversions.push_back(d); - return detail::Dynamic_Conversions::get().add_conversion(d); - } - - /** - * Add a new named Proxy_Function to the system - */ - bool add(const Proxy_Function &f, const std::string &name) - { - validate_object_name(name); - return add_function(f, name); - } - - /** - * Set the value of an object, by name. If the object - * is not available in the current scope it is created - */ - void add(const Boxed_Value &obj, const std::string &name) - { - validate_object_name(name); - StackData &stack = get_stack_data(); - - for (int i = static_cast(stack.size())-1; i >= 0; --i) + struct State { - std::map::const_iterator itr = stack[i].find(name); - if (itr != stack[i].end()) + std::map > m_functions; + std::map m_global_objects; + Type_Name_Map m_types; + std::set m_reserved_words; + }; + + Dispatch_Engine() + : m_place_holder(boost::shared_ptr(new dispatch::Placeholder_Object())) + { + } + + ~Dispatch_Engine() + { + detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end()); + } + + /** + * Add a new conversion for upcasting to a base class + */ + void add(const Dynamic_Cast_Conversion &d) + { + m_conversions.push_back(d); + return detail::Dynamic_Conversions::get().add_conversion(d); + } + + /** + * Add a new named Proxy_Function to the system + */ + bool add(const Proxy_Function &f, const std::string &name) + { + validate_object_name(name); + return add_function(f, name); + } + + /** + * Set the value of an object, by name. If the object + * is not available in the current scope it is created + */ + void add(const Boxed_Value &obj, const std::string &name) + { + validate_object_name(name); + StackData &stack = get_stack_data(); + + for (int i = static_cast(stack.size())-1; i >= 0; --i) { - stack[i][name] = obj; - return; + std::map::const_iterator itr = stack[i].find(name); + if (itr != stack[i].end()) + { + stack[i][name] = obj; + return; + } + } + + add_object(name, obj); + } + + /** + * Adds a named object to the current scope + */ + void add_object(const std::string &name, const Boxed_Value &obj) + { + StackData &stack = get_stack_data(); + validate_object_name(name); + stack.back()[name] = obj; + } + + /** + * Adds a new global shared object, between all the threads + */ + void add_global_const(const Boxed_Value &obj, const std::string &name) + { + validate_object_name(name); + if (!obj.is_const()) + { + throw exception::global_non_const(); + } + + chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + + m_state.m_global_objects[name] = obj; + } + + /** + * Adds a new scope to the stack + */ + void new_scope() + { + StackData &stack = get_stack_data(); + stack.push_back(Scope()); + } + + /** + * Pops the current scope from the stack + */ + void pop_scope() + { + StackData &stack = get_stack_data(); + if (stack.size() > 1) + { + stack.pop_back(); + } else { + throw std::range_error("Unable to pop global stack"); } } - add_object(name, obj); - } - - /** - * Adds a named object to the current scope - */ - void add_object(const std::string &name, const Boxed_Value &obj) - { - StackData &stack = get_stack_data(); - validate_object_name(name); - stack.back()[name] = obj; - } - - /** - * Adds a new global shared object, between all the threads - */ - void add_global_const(const Boxed_Value &obj, const std::string &name) - { - validate_object_name(name); - if (!obj.is_const()) + /** + * Swaps out the stack with a new stack + * \returns the old stack + * \param[in] s The new stack + */ + Stack set_stack(const Stack &s) { - throw global_non_const(); + Stack old = m_stack_holder->stack; + m_stack_holder->stack = s; + return old; } -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_global_object_mutex); -#endif - - m_state.m_global_objects[name] = obj; - } - - /** - * Adds a new scope to the stack - */ - void new_scope() - { - StackData &stack = get_stack_data(); - stack.push_back(Scope()); - } - - /** - * Pops the current scope from the stack - */ - void pop_scope() - { - StackData &stack = get_stack_data(); - if (stack.size() > 1) + Stack new_stack() const { - stack.pop_back(); - } else { - throw std::range_error("Unable to pop global stack"); - } - } - - /** - * Swaps out the stack with a new stack - * \returns the old stack - * \param[in] s The new stack - */ - Stack set_stack(const Stack &s) - { - Stack old = m_stack_holder->stack; - m_stack_holder->stack = s; - return old; - } - - Stack new_stack() const - { - Stack s(new Stack::element_type()); - s->push_back(Scope()); - return s; - } - - Stack get_stack() const - { - return m_stack_holder->stack; - } - - /** - * Searches the current stack for an object of the given name - * includes a special overload for the _ place holder object to - * ensure that it is always in scope. - */ - Boxed_Value get_object(const std::string &name) const - { - // Is it a placeholder object? - if (name == "_") - { - return m_place_holder; + Stack s(new Stack::element_type()); + s->push_back(Scope()); + return s; } - StackData &stack = get_stack_data(); - - // Is it in the stack? - for (int i = static_cast(stack.size())-1; i >= 0; --i) + Stack get_stack() const { - std::map::const_iterator stackitr = stack[i].find(name); - if (stackitr != stack[i].end()) + return m_stack_holder->stack; + } + + /** + * Searches the current stack for an object of the given name + * includes a special overload for the _ place holder object to + * ensure that it is always in scope. + */ + Boxed_Value get_object(const std::string &name) const + { + // Is it a placeholder object? + if (name == "_") { - return stackitr->second; + return m_place_holder; + } + + StackData &stack = get_stack_data(); + + // Is it in the stack? + for (int i = static_cast(stack.size())-1; i >= 0; --i) + { + std::map::const_iterator stackitr = stack[i].find(name); + if (stackitr != stack[i].end()) + { + return stackitr->second; + } + } + + // Is the value we are looking for a global? + { + chaiscript::detail::threading::shared_lock l(m_global_object_mutex); + + std::map::const_iterator itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + return itr->second; + } + } + + // If all that failed, then check to see if it's a function + std::vector funcs = get_function(name); + + if (funcs.empty()) + { + throw std::range_error("Object not known: " + name); + } else { + if (funcs.size() == 1) + { + // Return the first item if there is only one, + // no reason to take the cast of the extra level of dispatch + return const_var(*funcs.begin()); + } else { + return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs))); + } } } - // Is the value we are looking for a global? + /** + * Registers a new named type + */ + void add(const Type_Info &ti, const std::string &name) { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_global_object_mutex); -#endif + add_global_const(const_var(ti), name + "_type"); - std::map::const_iterator itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) + chaiscript::detail::threading::unique_lock l(m_mutex); + + m_state.m_types.insert(std::make_pair(name, ti)); + } + + /** + * Returns the type info for a named type + */ + Type_Info get_type(const std::string &name) const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + Type_Name_Map::const_iterator itr = m_state.m_types.find(name); + + if (itr != m_state.m_types.end()) { return itr->second; } + + throw std::range_error("Type Not Known"); } - // If all that failed, then check to see if it's a function - std::vector funcs = get_function(name); - - if (funcs.empty()) + /** + * Returns the registered name of a known type_info object + * compares the "bare_type_info" for the broadest possible + * match + */ + std::string get_type_name(const Type_Info &ti) const { - throw std::range_error("Object not known: " + name); - } else { - if (funcs.size() == 1) + chaiscript::detail::threading::shared_lock l(m_mutex); + + for (Type_Name_Map::const_iterator itr = m_state.m_types.begin(); + itr != m_state.m_types.end(); + ++itr) { - // Return the first item if there is only one, - // no reason to take the cast of the extra level of dispatch - return const_var(*funcs.begin()); - } else { - return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs))); + if (itr->second.bare_equal(ti)) + { + return itr->first; + } } - } - } - /** - * Registers a new named type - */ - void add(const Type_Info &ti, const std::string &name) - { - add_global_const(const_var(ti), name + "_type"); - -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif - - m_state.m_types.insert(std::make_pair(name, ti)); - } - - /** - * Returns the type info for a named type - */ - Type_Info get_type(const std::string &name) const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - - Type_Name_Map::const_iterator itr = m_state.m_types.find(name); - - if (itr != m_state.m_types.end()) - { - return itr->second; + return ti.bare_name(); } - throw std::range_error("Type Not Known"); - } - - /** - * Returns the registered name of a known type_info object - * compares the "bare_type_info" for the broadest possible - * match - */ - std::string get_type_name(const Type_Info &ti) const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - - for (Type_Name_Map::const_iterator itr = m_state.m_types.begin(); - itr != m_state.m_types.end(); - ++itr) + /** + * Return all registered types + */ + std::vector > get_types() const { - if (itr->second.bare_equal(ti)) + chaiscript::detail::threading::shared_lock l(m_mutex); + + return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); + } + + /** + * Return a function by name + */ + std::vector< Proxy_Function > + get_function(const std::string &t_name) const { - return itr->first; + chaiscript::detail::threading::shared_lock l(m_mutex); + + const std::map > &funs = get_functions_int(); + + std::map >::const_iterator itr + = funs.find(t_name); + + if (itr != funs.end()) + { + return itr->second; + } else { + return std::vector(); + } + } + + /** + * Return true if a function exists + */ + bool function_exists(const std::string &name) const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const std::map > &functions = get_functions_int(); + return functions.find(name) != functions.end(); } - return ti.bare_name(); - } - - /** - * Return all registered types - */ - std::vector > get_types() const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - - return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); - } - - /** - * Return a function by name - */ - std::vector< Proxy_Function > - get_function(const std::string &t_name) const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - - const std::map > &funs = get_functions_int(); - - std::map >::const_iterator itr - = funs.find(t_name); - - if (itr != funs.end()) + /** + * Get a vector of all registered functions + */ + std::vector > get_functions() const { - return itr->second; - } else { - return std::vector(); - } + chaiscript::detail::threading::shared_lock l(m_mutex); - } + std::vector > rets; - /** - * Return true if a function exists - */ - bool function_exists(const std::string &name) const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + const std::map > &functions = get_functions_int(); - const std::map > &functions = get_functions_int(); - return functions.find(name) != functions.end(); - } - - /** - * Get a vector of all registered functions - */ - std::vector > get_functions() const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - std::vector > rets; - - const std::map > &functions = get_functions_int(); - - for (std::map >::const_iterator itr = functions.begin(); - itr != functions.end(); - ++itr) - { - for (std::vector::const_iterator itr2 = itr->second.begin(); - itr2 != itr->second.end(); - ++itr2) + for (std::map >::const_iterator itr = functions.begin(); + itr != functions.end(); + ++itr) { - rets.push_back(std::make_pair(itr->first, *itr2)); + for (std::vector::const_iterator itr2 = itr->second.begin(); + itr2 != itr->second.end(); + ++itr2) + { + rets.push_back(std::make_pair(itr->first, *itr2)); + } } + + return rets; } - return rets; - } + void add_reserved_word(const std::string &name) + { + chaiscript::detail::threading::unique_lock l(m_mutex); - void add_reserved_word(const std::string &name) - { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + m_state.m_reserved_words.insert(name); + } - m_state.m_reserved_words.insert(name); - } + Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const + { + std::vector functions = get_function(t_name); - Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const - { - std::vector functions = get_function(t_name); + return dispatch::dispatch(functions.begin(), functions.end(), params); + } - return dispatch(functions.begin(), functions.end(), params); - } + Boxed_Value call_function(const std::string &t_name) const + { + return call_function(t_name, std::vector()); + } - Boxed_Value call_function(const std::string &t_name) const - { - return call_function(t_name, std::vector()); - } + Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const + { + std::vector params; + params.push_back(p1); + return call_function(t_name, params); + } - Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const - { - std::vector params; - params.push_back(p1); - return call_function(t_name, params); - } + Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const + { + std::vector params; + params.push_back(p1); + params.push_back(p2); + return call_function(t_name, params); + } - Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const - { - std::vector params; - params.push_back(p1); - params.push_back(p2); - return call_function(t_name, params); - } - - /** - * Dump object info to stdout - */ + /** + * Dump object info to stdout + */ void dump_object(Boxed_Value o) const { Type_Info ti = o.get_type_info(); std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl; } - /** - * Dump type info to stdout - */ + /** + * Dump type info to stdout + */ void dump_type(const Type_Info &type) const { std::cout << (type.is_const()?"const ":"") << get_type_name(type); } - /** - * Dump function to stdout - */ + /** + * Dump function to stdout + */ void dump_function(const std::pair &f) const { std::vector params = f.second->get_param_types(); @@ -706,9 +702,9 @@ namespace chaiscript std::cout << ") " << std::endl; } - /** - * Dump all system info to stdout - */ + /** + * Dump all system info to stdout + */ void dump_system() const { std::cout << "Registered Types: " << std::endl; @@ -735,249 +731,239 @@ namespace chaiscript std::cout << std::endl; } - /** - * return true if the Boxed_Value matches the registered type by name - */ - bool is_type(Boxed_Value r, const std::string &user_typename) const - { - try { - if (get_type(user_typename).bare_equal(r.get_type_info())) - { - return true; - } - } catch (const std::range_error &) { - } - - try { - const Dynamic_Object &d = boxed_cast(r); - return d.get_type_name() == user_typename; - } catch (const std::bad_cast &) { - } - - return false; - } - - std::string type_name(Boxed_Value obj) const - { - return get_type_name(obj.get_type_info()); - } - - State get_state() - { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); - boost::unique_lock l2(m_global_object_mutex); -#endif - - return m_state; - } - - void set_state(const State &t_state) - { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); - boost::unique_lock l2(m_global_object_mutex); -#endif - - m_state = t_state; - } - - - private: - /** - * Returns the current stack - * make const/non const versions - */ - StackData &get_stack_data() const - { - return *(m_stack_holder->stack); - } - - const std::map > &get_functions_int() const - { - return m_state.m_functions; - } - - std::map > &get_functions_int() - { - return m_state.m_functions; - } - - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) - { - const std::vector lhsparamtypes = lhs->get_param_types(); - const std::vector rhsparamtypes = rhs->get_param_types(); - - const int lhssize = lhsparamtypes.size(); - const int rhssize = rhsparamtypes.size(); - - const Type_Info boxed_type = user_type(); - const Type_Info boxed_pod_type = user_type(); - - boost::shared_ptr dynamic_lhs(boost::dynamic_pointer_cast(lhs)); - boost::shared_ptr dynamic_rhs(boost::dynamic_pointer_cast(rhs)); - - if (dynamic_lhs && dynamic_rhs) + /** + * return true if the Boxed_Value matches the registered type by name + */ + bool is_type(Boxed_Value r, const std::string &user_typename) const { - if (dynamic_lhs->get_guard()) - { - if (dynamic_rhs->get_guard()) + try { + if (get_type(user_typename).bare_equal(r.get_type_info())) { - return false; - } else { return true; } - } else { - return false; + } catch (const std::range_error &) { + } + + try { + const dispatch::Dynamic_Object &d = boxed_cast(r); + return d.get_type_name() == user_typename; + } catch (const std::bad_cast &) { } - } - if (dynamic_lhs && !dynamic_rhs) - { return false; } - if (!dynamic_lhs && dynamic_rhs) + std::string type_name(Boxed_Value obj) const { - return true; + return get_type_name(obj.get_type_info()); + } + + State get_state() + { + chaiscript::detail::threading::shared_lock l(m_mutex); + chaiscript::detail::threading::shared_lock l2(m_global_object_mutex); + + return m_state; + } + + void set_state(const State &t_state) + { + chaiscript::detail::threading::unique_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l2(m_global_object_mutex); + + m_state = t_state; } - - for (int i = 1; i < lhssize && i < rhssize; ++i) + private: + /** + * Returns the current stack + * make const/non const versions + */ + StackData &get_stack_data() const { - const Type_Info lt = lhsparamtypes[i]; - const Type_Info rt = rhsparamtypes[i]; + return *(m_stack_holder->stack); + } - if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) - { - continue; // The first two types are essentially the same, next iteration - } + const std::map > &get_functions_int() const + { + return m_state.m_functions; + } - // const is after non-const for the same type - if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) - { - return false; - } + std::map > &get_functions_int() + { + return m_state.m_functions; + } - if (lt.bare_equal(rt) && !lt.is_const()) - { - return true; - } + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + { + const std::vector lhsparamtypes = lhs->get_param_types(); + const std::vector rhsparamtypes = rhs->get_param_types(); - // boxed_values are sorted last - if (lt.bare_equal(boxed_type)) - { - return false; - } + const int lhssize = lhsparamtypes.size(); + const int rhssize = rhsparamtypes.size(); - if (rt.bare_equal(boxed_type)) + const Type_Info boxed_type = user_type(); + const Type_Info boxed_pod_type = user_type(); + + boost::shared_ptr dynamic_lhs(boost::dynamic_pointer_cast(lhs)); + boost::shared_ptr dynamic_rhs(boost::dynamic_pointer_cast(rhs)); + + if (dynamic_lhs && dynamic_rhs) { - if (lt.bare_equal(boxed_pod_type)) - { - return true; - } - return true; - } - - if (lt.bare_equal(boxed_pod_type)) - { - return false; - } - - if (rt.bare_equal(boxed_pod_type)) - { - return true; - } - - // otherwise, we want to sort by typeid - return lt < rt; - } - - return false; - } - - - /** - * Throw a reserved_word exception if the name is not allowed - */ - void validate_object_name(const std::string &name) const - { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif - - if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) - { - throw reserved_word_error(name); - } - } - - /** - * Implementation detail for adding a function. Returns - * true if the function was added, false if a function with the - * same signature and name already exists. - */ - bool add_function(const Proxy_Function &t_f, const std::string &t_name) - { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif - - std::map > &funcs = get_functions_int(); - - std::map >::iterator itr - = funcs.find(t_name); - - if (itr != funcs.end()) - { - std::vector &vec = itr->second; - for (std::vector::const_iterator itr2 = vec.begin(); - itr2 != vec.end(); - ++itr2) - { - if ((*t_f) == *(*itr2)) + if (dynamic_lhs->get_guard()) { + if (dynamic_rhs->get_guard()) + { + return false; + } else { + return true; + } + } else { return false; } } - vec.push_back(t_f); - std::stable_sort(vec.begin(), vec.end(), &function_less_than); - } else { - std::vector vec; - vec.push_back(t_f); - funcs.insert(std::make_pair(t_name, vec)); + if (dynamic_lhs && !dynamic_rhs) + { + return false; + } + + if (!dynamic_lhs && dynamic_rhs) + { + return true; + } + + + + for (int i = 1; i < lhssize && i < rhssize; ++i) + { + const Type_Info lt = lhsparamtypes[i]; + const Type_Info rt = rhsparamtypes[i]; + + if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + { + continue; // The first two types are essentially the same, next iteration + } + + // const is after non-const for the same type + if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) + { + return false; + } + + if (lt.bare_equal(rt) && !lt.is_const()) + { + return true; + } + + // boxed_values are sorted last + if (lt.bare_equal(boxed_type)) + { + return false; + } + + if (rt.bare_equal(boxed_type)) + { + if (lt.bare_equal(boxed_pod_type)) + { + return true; + } + return true; + } + + if (lt.bare_equal(boxed_pod_type)) + { + return false; + } + + if (rt.bare_equal(boxed_pod_type)) + { + return true; + } + + // otherwise, we want to sort by typeid + return lt < rt; + } + + return false; } - return true; - } -#ifndef CHAISCRIPT_NO_THREADS - mutable boost::shared_mutex m_mutex; - mutable boost::shared_mutex m_global_object_mutex; -#endif - - struct Stack_Holder - { - Stack_Holder() - : stack(new StackData()) + /** + * Throw a reserved_word exception if the name is not allowed + */ + void validate_object_name(const std::string &name) const { - stack->push_back(Scope()); + chaiscript::detail::threading::shared_lock l(m_mutex); + + if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) + { + throw exception::reserved_word_error(name); + } } - Stack stack; - }; + /** + * Implementation detail for adding a function. Returns + * true if the function was added, false if a function with the + * same signature and name already exists. + */ + bool add_function(const Proxy_Function &t_f, const std::string &t_name) + { + chaiscript::detail::threading::unique_lock l(m_mutex); - std::vector m_conversions; - chaiscript::detail::threading::Thread_Storage m_stack_holder; + std::map > &funcs = get_functions_int(); + + std::map >::iterator itr + = funcs.find(t_name); + + if (itr != funcs.end()) + { + std::vector &vec = itr->second; + for (std::vector::const_iterator itr2 = vec.begin(); + itr2 != vec.end(); + ++itr2) + { + if ((*t_f) == *(*itr2)) + { + return false; + } + } + + vec.push_back(t_f); + std::stable_sort(vec.begin(), vec.end(), &function_less_than); + } else { + std::vector vec; + vec.push_back(t_f); + funcs.insert(std::make_pair(t_name, vec)); + } + + return true; + } + + mutable chaiscript::detail::threading::shared_mutex m_mutex; + mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; + + struct Stack_Holder + { + Stack_Holder() + : stack(new StackData()) + { + stack->push_back(Scope()); + } + + Stack stack; + }; + + std::vector m_conversions; + chaiscript::detail::threading::Thread_Storage m_stack_holder; - State m_state; - - Boxed_Value m_place_holder; - }; + State m_state; + Boxed_Value m_place_holder; + }; + } } #endif diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 5bbb6fe7..30f7d891 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -1,3 +1,9 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) +// and Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ @@ -9,10 +15,6 @@ #include #include -#ifndef CHAISCRIPT_NO_THREADS -#include -#endif - namespace chaiscript { namespace exception @@ -150,9 +152,7 @@ namespace chaiscript template void cleanup(InItr begin, const InItr &end) { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); while (begin != end) { @@ -167,28 +167,22 @@ namespace chaiscript void add_conversion(const boost::shared_ptr &conversion) { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); m_conversions.insert(conversion.get()); } - bool has_conversion(const Type_Info &base, const Type_Info &derived) + bool has_conversion(const Type_Info &base, const Type_Info &derived) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); return find(base, derived) != m_conversions.end(); } - Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) + Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); std::set::const_iterator itr = find(base, derived); @@ -205,7 +199,7 @@ namespace chaiscript Dynamic_Conversions() {} std::set::const_iterator find( - const Type_Info &base, const Type_Info &derived) + const Type_Info &base, const Type_Info &derived) const { for (std::set::const_iterator itr = m_conversions.begin(); itr != m_conversions.end(); @@ -219,9 +213,8 @@ namespace chaiscript return m_conversions.end(); } -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_mutex m_mutex; -#endif + + mutable chaiscript::detail::threading::shared_mutex m_mutex; std::set m_conversions; }; } @@ -248,29 +241,31 @@ namespace chaiscript return detail::Dynamic_Conversions::create(); } - template - bool dynamic_cast_converts() + namespace detail { - return dynamic_cast_converts(user_type(), user_type()); - } + template + bool dynamic_cast_converts() + { + return dynamic_cast_converts(user_type(), user_type()); + } - static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) - { - return detail::Dynamic_Conversions::get().has_conversion(base, derived); - } - - template - Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) - { - try { - return detail::Dynamic_Conversions::get().get_conversion(user_type(), derived.get_type_info())->convert(derived); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) + { + return detail::Dynamic_Conversions::get().has_conversion(base, derived); } - } + template + Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) + { + try { + return detail::Dynamic_Conversions::get().get_conversion(user_type(), derived.get_type_info())->convert(derived); + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + } + } + } } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index fdccbbac..02690888 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -1,3 +1,9 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) +// and Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ @@ -5,270 +11,273 @@ namespace chaiscript { - class Dynamic_Object + namespace dispatch { - public: - Dynamic_Object(const std::string &t_type_name) - : m_type_name(t_type_name) - { - } - - std::string get_type_name() const - { - return m_type_name; - } - - Boxed_Value get_attr(const std::string &t_attr_name) - { - return m_attrs[t_attr_name]; - } - - std::map get_attrs() - { - return m_attrs; - } - - private: - std::string m_type_name; - - std::map m_attrs; - }; - - namespace detail - { - struct Dynamic_Object_Attribute - { - static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name, - Dynamic_Object &t_do) - { - if (t_do.get_type_name() != t_type_name) - { - throw exception::bad_boxed_cast("Dynamic object type mismatch"); - } - - return t_do.get_attr(t_attr_name); - } - }; - - /** - * A Proxy_Function implementation designed for calling a function - * that is automatically guarded based on the first param based on the - * param's type name - */ - class Dynamic_Object_Function : public Proxy_Function_Base + class Dynamic_Object { public: - Dynamic_Object_Function( - const std::string &t_type_name, - const Proxy_Function &t_func, - const boost::optional &t_ti = boost::optional()) - : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), - m_type_name(t_type_name), m_func(t_func), m_ti(t_ti) + Dynamic_Object(const std::string &t_type_name) + : m_type_name(t_type_name) + { + } + + std::string get_type_name() const + { + return m_type_name; + } + + Boxed_Value get_attr(const std::string &t_attr_name) + { + return m_attrs[t_attr_name]; + } + + std::map get_attrs() + { + return m_attrs; + } + + private: + std::string m_type_name; + + std::map m_attrs; + }; + + namespace detail + { + struct Dynamic_Object_Attribute + { + static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name, + Dynamic_Object &t_do) + { + if (t_do.get_type_name() != t_type_name) + { + throw exception::bad_boxed_cast("Dynamic object type mismatch"); + } + + return t_do.get_attr(t_attr_name); + } + }; + + /** + * A Proxy_Function implementation designed for calling a function + * that is automatically guarded based on the first param based on the + * param's type name + */ + class Dynamic_Object_Function : public Proxy_Function_Base + { + public: + Dynamic_Object_Function( + const std::string &t_type_name, + const Proxy_Function &t_func, + const boost::optional &t_ti = boost::optional()) + : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), + m_type_name(t_type_name), m_func(t_func), m_ti(t_ti) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); } - virtual ~Dynamic_Object_Function() {} + virtual ~Dynamic_Object_Function() {} - virtual bool operator==(const Proxy_Function_Base &f) const - { - const Dynamic_Object_Function *df = dynamic_cast(&f); - if (df) + virtual bool operator==(const Proxy_Function_Base &f) const { - return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); - } else { - return false; - } - } - - virtual bool call_match(const std::vector &vals) const - { - if (dynamic_object_typename_match(vals, m_type_name, m_ti)) - { - return m_func->call_match(vals); - } else { - return false; - } - } - - virtual std::vector get_contained_functions() const - { - std::vector fs; - fs.push_back(m_func); - return fs; - } - - - virtual int get_arity() const - { - return m_func->get_arity(); - } - - virtual std::string annotation() const - { - return m_func->annotation(); - } - - - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - if (dynamic_object_typename_match(params, m_type_name, m_ti)) - { - return (*m_func)(params); - } else { - throw exception::guard_error(); - } - } - - virtual bool compare_first_type(const Boxed_Value &bv) const - { - return dynamic_object_typename_match(bv, m_type_name, m_ti); - } - - private: - static std::vector build_param_types( - const std::vector &t_inner_types, boost::optional t_objectti) - { - if (t_objectti) - { - std::vector types(t_inner_types); - - assert(types.size() > 1); - assert(types[1].bare_equal(user_type())); - types[1] = *t_objectti; - return types; - } else { - return t_inner_types; - } - } - - static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const boost::optional &ti) - { - static Type_Info doti = user_type(); - if (bv.get_type_info().bare_equal(doti)) - { - try { - const Dynamic_Object &d = boxed_cast(bv); - return name == "Dynamic_Object" || d.get_type_name() == name; - } catch (const std::bad_cast &) { - return false; - } - } else { - if (ti) + const Dynamic_Object_Function *df = dynamic_cast(&f); + if (df) { - return bv.get_type_info().bare_equal(*ti); + return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); } else { return false; } } - } - - static bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, - const boost::optional &ti) - { - if (bvs.size() > 0) + virtual bool call_match(const std::vector &vals) const { - return dynamic_object_typename_match(bvs[0], name, ti); - } else { - return false; + if (dynamic_object_typename_match(vals, m_type_name, m_ti)) + { + return m_func->call_match(vals); + } else { + return false; + } + } + + virtual std::vector get_contained_functions() const + { + std::vector fs; + fs.push_back(m_func); + return fs; } - } - - std::string m_type_name; - Proxy_Function m_func; - boost::optional m_ti; - - }; - /** - * A Proxy_Function implementation designed for creating a new - * Dynamic_Object - * that is automatically guarded based on the first param based on the - * param's type name - */ - class Dynamic_Object_Constructor : public Proxy_Function_Base - { - public: - Dynamic_Object_Constructor( - const std::string &t_type_name, - const Proxy_Function &t_func) - : Proxy_Function_Base(build_type_list(t_func->get_param_types())), - m_type_name(t_type_name), m_func(t_func) + virtual int get_arity() const + { + return m_func->get_arity(); + } + + virtual std::string annotation() const + { + return m_func->annotation(); + } + + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + if (dynamic_object_typename_match(params, m_type_name, m_ti)) + { + return (*m_func)(params); + } else { + throw exception::guard_error(); + } + } + + virtual bool compare_first_type(const Boxed_Value &bv) const + { + return dynamic_object_typename_match(bv, m_type_name, m_ti); + } + + private: + static std::vector build_param_types( + const std::vector &t_inner_types, boost::optional t_objectti) + { + if (t_objectti) + { + std::vector types(t_inner_types); + + assert(types.size() > 1); + assert(types[1].bare_equal(user_type())); + types[1] = *t_objectti; + return types; + } else { + return t_inner_types; + } + } + + static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, + const boost::optional &ti) + { + static Type_Info doti = user_type(); + if (bv.get_type_info().bare_equal(doti)) + { + try { + const Dynamic_Object &d = boxed_cast(bv); + return name == "Dynamic_Object" || d.get_type_name() == name; + } catch (const std::bad_cast &) { + return false; + } + } else { + if (ti) + { + return bv.get_type_info().bare_equal(*ti); + } else { + return false; + } + } + + } + + static bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, + const boost::optional &ti) + { + if (bvs.size() > 0) + { + return dynamic_object_typename_match(bvs[0], name, ti); + } else { + return false; + } + } + + std::string m_type_name; + Proxy_Function m_func; + boost::optional m_ti; + + }; + + + /** + * A Proxy_Function implementation designed for creating a new + * Dynamic_Object + * that is automatically guarded based on the first param based on the + * param's type name + */ + class Dynamic_Object_Constructor : public Proxy_Function_Base + { + public: + Dynamic_Object_Constructor( + const std::string &t_type_name, + const Proxy_Function &t_func) + : Proxy_Function_Base(build_type_list(t_func->get_param_types())), + m_type_name(t_type_name), m_func(t_func) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); } - static std::vector build_type_list(const std::vector &tl) - { - std::vector::const_iterator begin = tl.begin(); - std::vector::const_iterator end = tl.end(); - - if (begin != end) + static std::vector build_type_list(const std::vector &tl) { - ++begin; + std::vector::const_iterator begin = tl.begin(); + std::vector::const_iterator end = tl.end(); + + if (begin != end) + { + ++begin; + } + + return std::vector(begin, end); } - return std::vector(begin, end); - } + virtual ~Dynamic_Object_Constructor() {} - virtual ~Dynamic_Object_Constructor() {} - - virtual bool operator==(const Proxy_Function_Base &f) const - { - const Dynamic_Object_Constructor *dc = dynamic_cast(&f); - if (dc) + virtual bool operator==(const Proxy_Function_Base &f) const { - return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); - } else { - return false; + const Dynamic_Object_Constructor *dc = dynamic_cast(&f); + if (dc) + { + return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); + } else { + return false; + } } - } - virtual bool call_match(const std::vector &vals) const - { - std::vector new_vals; - new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name))); - new_vals.insert(new_vals.end(), vals.begin(), vals.end()); + virtual bool call_match(const std::vector &vals) const + { + std::vector new_vals; + new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name))); + new_vals.insert(new_vals.end(), vals.begin(), vals.end()); - return m_func->call_match(new_vals); - } + return m_func->call_match(new_vals); + } - virtual int get_arity() const - { - // "this" is not considered part of the arity - return m_func->get_arity() - 1; - } + virtual int get_arity() const + { + // "this" is not considered part of the arity + return m_func->get_arity() - 1; + } - virtual std::string annotation() const - { - return m_func->annotation(); - } + virtual std::string annotation() const + { + return m_func->annotation(); + } - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - std::vector new_params; - chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); - new_params.push_back(bv); - new_params.insert(new_params.end(), params.begin(), params.end()); + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + std::vector new_params; + chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); + new_params.push_back(bv); + new_params.insert(new_params.end(), params.begin(), params.end()); - (*m_func)(new_params); + (*m_func)(new_params); - return bv; - } + return bv; + } - private: - std::string m_type_name; - Proxy_Function m_func; + private: + std::string m_type_name; + Proxy_Function m_func; - }; + }; + } } } #endif diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 51899d14..9dea81cf 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -4,8 +4,8 @@ // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com -#ifndef __function_call_hpp__ -#define __function_call_hpp__ +#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ +#define CHAISCRIPT_FUNCTION_CALL_HPP_ #include #include @@ -20,37 +20,39 @@ namespace chaiscript { - /** - * Build a function caller that knows how to dispatch on a set of functions - * example: - * boost::function f = - * build_function_caller(dispatchkit.get_function("print")); - * \returns A boost::function object for dispatching - * \param[in] funcs the set of functions to dispatch on. - */ - template - boost::function + namespace dispatch + { + /** + * Build a function caller that knows how to dispatch on a set of functions + * example: + * boost::function f = + * build_function_caller(dispatchkit.get_function("print")); + * \returns A boost::function object for dispatching + * \param[in] funcs the set of functions to dispatch on. + */ + template + boost::function functor(const std::vector &funcs) { FunctionType *p=0; return detail::build_function_caller_helper(p, funcs); } - /** - * Build a function caller for a particular Proxy_Function object - * useful in the case that a function is being pass out from scripting back - * into code - * example: - * void my_function(Proxy_Function f) - * { - * boost::function local_f = - * build_function_caller(f); - * } - * \returns A boost::function object for dispatching - * \param[in] func A function to execute. - */ - template - boost::function + /** + * Build a function caller for a particular Proxy_Function object + * useful in the case that a function is being pass out from scripting back + * into code + * example: + * void my_function(Proxy_Function f) + * { + * boost::function local_f = + * build_function_caller(f); + * } + * \returns A boost::function object for dispatching + * \param[in] func A function to execute. + */ + template + boost::function functor(Const_Proxy_Function func) { std::vector funcs; @@ -58,76 +60,76 @@ namespace chaiscript return functor(funcs); } - /** - * Helper for automatically unboxing a Boxed_Value that contains a function object - * and creating a typesafe C++ function caller from it. - */ - template - boost::function + /** + * Helper for automatically unboxing a Boxed_Value that contains a function object + * and creating a typesafe C++ function caller from it. + */ + template + boost::function functor(const Boxed_Value &bv) { return functor(boxed_cast(bv)); } + } namespace detail{ /** - * Cast helper to handle automatic casting to const boost::function & - */ + * Cast helper to handle automatic casting to const boost::function & + */ template struct Cast_Helper &> { typedef boost::function Result_Type; - + static Result_Type cast(const Boxed_Value &ob) { if (ob.get_type_info().bare_equal(user_type())) { - return functor(ob); + return dispatch::functor(ob); } else { return Cast_Helper_Inner &>::cast(ob); } } }; - + /** - * Cast helper to handle automatic casting to boost::function - */ + * Cast helper to handle automatic casting to boost::function + */ template struct Cast_Helper > { typedef boost::function Result_Type; - + static Result_Type cast(const Boxed_Value &ob) { if (ob.get_type_info().bare_equal(user_type())) { - return functor(ob); + return dispatch::functor(ob); } else { return Cast_Helper_Inner >::cast(ob); } } }; - + /** - * Cast helper to handle automatic casting to const boost::function - */ + * Cast helper to handle automatic casting to const boost::function + */ template struct Cast_Helper > { typedef boost::function Result_Type; - + static Result_Type cast(const Boxed_Value &ob) { if (ob.get_type_info().bare_equal(user_type())) { - return functor(ob); + return dispatch::functor(ob); } else { return Cast_Helper_Inner >::cast(ob); } } }; } - } #endif diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index e9f977cb..49a877ae 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -1,12 +1,12 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include -#define addparam(z,n,text) params.push_back(boost::is_reference::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) )); +#define addparam(z,n,text) params.push_back((boost::is_reference::value&&!(boost::is_same::type>::type>::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)) @@ -23,34 +23,38 @@ namespace chaiscript { - namespace detail + namespace dispatch { - /** - * Internal helper class for handling the return - * value of a build_function_caller - */ - template - struct Function_Caller_Ret - { - static Ret call(const std::vector &t_funcs, - const std::vector ¶ms) - { - return boxed_cast(dispatch(t_funcs, params)); - } - }; + namespace detail + { - /** - * Specialization for void return types - */ - template<> - struct Function_Caller_Ret - { - static void call(const std::vector &t_funcs, - const std::vector ¶ms) + /** + * Internal helper class for handling the return + * value of a build_function_caller + */ + template + struct Function_Caller_Ret { - dispatch(t_funcs, params); - } - }; + static Ret call(const std::vector &t_funcs, + const std::vector ¶ms) + { + return boxed_cast(dispatch::dispatch(t_funcs, params)); + } + }; + + /** + * Specialization for void return types + */ + template<> + struct Function_Caller_Ret + { + static void call(const std::vector &t_funcs, + const std::vector ¶ms) + { + dispatch::dispatch(t_funcs, params); + } + }; + } } } @@ -64,47 +68,49 @@ namespace chaiscript namespace chaiscript { - namespace detail + namespace dispatch { - /** - * used internally for unwrapping a function call's types - */ - template - Ret function_caller(const std::vector &funcs - BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) - { - std::vector params; - - BOOST_PP_REPEAT(n, addparam, ~) - - return Function_Caller_Ret::call(funcs, params); - } - - /** - * used internally for unwrapping a function call's types - */ - template - boost::function - build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector &funcs) - { - if (funcs.size() == 1) + namespace detail + { + /** + * used internally for unwrapping a function call's types + */ + template + Ret function_caller(const std::vector &funcs + BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) { - boost::shared_ptr > pfi = - boost::dynamic_pointer_cast > - (funcs[0]); + std::vector params; - if (pfi) - { - return pfi->internal_function(); - } - // looks like this either wasn't a Proxy_Function_Impl or the types didn't match - // we cannot make any other guesses or assumptions really, so continuing + BOOST_PP_REPEAT(n, addparam, ~) + + return Function_Caller_Ret::call(funcs, params); } - return boost::bind(&function_caller, funcs - BOOST_PP_ENUM_TRAILING(n, curry, ~)); - } + /** + * used internally for unwrapping a function call's types + */ + template + boost::function + build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector &funcs) + { + if (funcs.size() == 1) + { + boost::shared_ptr > pfi = + boost::dynamic_pointer_cast > + (funcs[0]); + if (pfi) + { + return pfi->internal_function(); + } + // looks like this either wasn't a Proxy_Function_Impl or the types didn't match + // we cannot make any other guesses or assumptions really, so continuing + } + + return boost::bind(&function_caller, funcs + BOOST_PP_ENUM_TRAILING(n, curry, ~)); + } + } } } #undef n diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index 5932e742..a79e5b05 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -27,7 +27,7 @@ namespace chaiscript { static Boxed_Value handle(const Ret &r) { - return Boxed_Value(r); + return const_var(r); } }; @@ -40,6 +40,15 @@ namespace chaiscript } }; + template + struct Handle_Return > + { + static Boxed_Value handle(const boost::shared_ptr &r) + { + return Boxed_Value(r); + } + }; + template struct Handle_Return &> { @@ -88,6 +97,18 @@ namespace chaiscript } }; + /** + * Used internally for handling a return value from a Proxy_Function call + */ + template<> + struct Handle_Return + { + static Boxed_Value handle(const Boxed_Value &r) + { + return r; + } + }; + /** * Used internally for handling a return value from a Proxy_Function call */ diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index fbecda8d..343da1e0 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -1,3 +1,9 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) +// and Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + #ifndef CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_ diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index ca5e394f..73e0afe2 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -26,7 +26,7 @@ namespace chaiscript Proxy_Function constructor() { T *f = 0; - return (detail::build_constructor_(f)); + return (dispatch::detail::build_constructor_(f)); } } @@ -35,30 +35,33 @@ namespace chaiscript namespace chaiscript { - namespace detail + namespace dispatch { - /** - * A constructor function, used for creating a new object - * of a given type with a given set of params - */ - template - boost::shared_ptr constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) - { - return boost::shared_ptr(new Class( BOOST_PP_ENUM_PARAMS(n, p) )); - } + namespace detail + { + /** + * A constructor function, used for creating a new object + * of a given type with a given set of params + */ + template + boost::shared_ptr constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) + { + return boost::shared_ptr(new Class( BOOST_PP_ENUM_PARAMS(n, p) )); + } - /** - * Helper function for build a constructor function - * example: - * dispatchengine.register_function(build_constructor, "MyClass"); - * \todo See if it is possible to make this not be a variadic function - */ - template - Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param))) - { - typedef boost::shared_ptr (sig)(BOOST_PP_ENUM_PARAMS(n, Param)); - return Proxy_Function(new Proxy_Function_Impl(boost::function(&(constructor_)))); - } + /** + * Helper function for build a constructor function + * example: + * dispatchengine.register_function(build_constructor, "MyClass"); + * \todo See if it is possible to make this not be a variadic function + */ + template + Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param))) + { + typedef boost::shared_ptr (sig)(BOOST_PP_ENUM_PARAMS(n, Param)); + return Proxy_Function(new Proxy_Function_Impl(boost::function(&(constructor_)))); + } + } } } #undef n diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index c8ec5493..97ef808b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -26,154 +26,157 @@ namespace chaiscript typedef boost::shared_ptr AST_NodePtr; - /** - * Helper for building a list of parameters for calling a Proxy_Function - * it does automatic conversion to Boxed_Value types via operator<< - * - * example usage: - * Boxed_Value retval = dispatch(dispatchengine.get_function("+"), - * chaiscript::Param_List_Builder() << 5 << 6); - */ - struct Param_List_Builder + namespace dispatch { - Param_List_Builder &operator<<(const Boxed_Value &so) + /** + * Helper for building a list of parameters for calling a Proxy_Function + * it does automatic conversion to Boxed_Value types via operator<< + * + * example usage: + * Boxed_Value retval = dispatch(dispatchengine.get_function("+"), + * chaiscript::Param_List_Builder() << 5 << 6); + */ + struct Param_List_Builder { - objects.push_back(so); - return *this; - } - - template - Param_List_Builder &operator<<(T t) + Param_List_Builder &operator<<(const Boxed_Value &so) { - objects.push_back(Boxed_Value(t)); + objects.push_back(so); return *this; } - operator const std::vector &() const - { - return objects; - } - - std::vector objects; - }; - - /** - * Pure virtual base class for all Proxy_Function implementations - * Proxy_Functions are a type erasure of type safe C++ - * function calls. At runtime parameter types are expected to be - * tested against passed in types. - * Dispatch_Engine only knows how to work with Proxy_Function, no other - * function classes. - */ - class Proxy_Function_Base - { - public: - virtual ~Proxy_Function_Base() {} - Boxed_Value operator()(const std::vector ¶ms) const - { - Boxed_Value bv = do_call(params); - bv.add_dependencies(params.begin(), params.end()); - return bv; - } - - /// Returns a vector containing all of the types of the parameters the function returns/takes - /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned - /// value containes exactly 1 Type_Info object: the return type - /// \returns the types of all parameters. - std::vector get_param_types() const { return m_types; } - - virtual bool operator==(const Proxy_Function_Base &) const = 0; - virtual bool call_match(const std::vector &vals) const = 0; - - virtual std::vector > get_contained_functions() const - { - return std::vector >(); - } - - - //! Return true if the function is a possible match - //! to the passed in values - bool filter(const std::vector &vals) const - { - int arity = get_arity(); - - if (arity < 0) + template + Param_List_Builder &operator<<(T t) { - return true; - } else if (size_t(arity) == vals.size()) { - if (arity == 0) + objects.push_back(Boxed_Value(t)); + return *this; + } + + operator const std::vector &() const + { + return objects; + } + + std::vector objects; + }; + + /** + * Pure virtual base class for all Proxy_Function implementations + * Proxy_Functions are a type erasure of type safe C++ + * function calls. At runtime parameter types are expected to be + * tested against passed in types. + * Dispatch_Engine only knows how to work with Proxy_Function, no other + * function classes. + */ + class Proxy_Function_Base + { + public: + virtual ~Proxy_Function_Base() {} + Boxed_Value operator()(const std::vector ¶ms) const + { + Boxed_Value bv = do_call(params); + bv.add_dependencies(params.begin(), params.end()); + return bv; + } + + /// Returns a vector containing all of the types of the parameters the function returns/takes + /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned + /// value containes exactly 1 Type_Info object: the return type + /// \returns the types of all parameters. + std::vector get_param_types() const { return m_types; } + + virtual bool operator==(const Proxy_Function_Base &) const = 0; + virtual bool call_match(const std::vector &vals) const = 0; + + virtual std::vector > get_contained_functions() const + { + return std::vector >(); + } + + + //! Return true if the function is a possible match + //! to the passed in values + bool filter(const std::vector &vals) const + { + int arity = get_arity(); + + if (arity < 0) + { + return true; + } else if (size_t(arity) == vals.size()) { + if (arity == 0) + { + return true; + } else { + return compare_first_type(vals[0]); + } + } else { + return false; + } + } + + /// \returns the number of arguments the function takes or -1 if it is variadic + virtual int get_arity() const = 0; + + virtual std::string annotation() const = 0; + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const = 0; + + Proxy_Function_Base(const std::vector &t_types) + : m_types(t_types) + { + } + + virtual bool compare_first_type(const Boxed_Value &bv) const + { + const std::vector &types = get_param_types(); + + if (types.size() < 2) + { + return true; + } + const Type_Info &ti = types[1]; + if (ti.is_undef() + || ti.bare_equal(user_type()) + || (!bv.get_type_info().is_undef() + && (ti.bare_equal(user_type()) + || ti.bare_equal(bv.get_type_info()) + || detail::dynamic_cast_converts(ti, bv.get_type_info()) + || bv.get_type_info().bare_equal(user_type >()) + ) + ) + ) { return true; } else { - return compare_first_type(vals[0]); + return false; } - } else { - return false; } - } - /// \returns the number of arguments the function takes or -1 if it is variadic - virtual int get_arity() const = 0; - - virtual std::string annotation() const = 0; - - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const = 0; - - Proxy_Function_Base(const std::vector &t_types) - : m_types(t_types) - { - } - - virtual bool compare_first_type(const Boxed_Value &bv) const - { - const std::vector &types = get_param_types(); - - if (types.size() < 2) + bool compare_types(const std::vector &tis, const std::vector &bvs) const { - return true; - } - const Type_Info &ti = types[1]; - if (ti.is_undef() - || ti.bare_equal(user_type()) - || (!bv.get_type_info().is_undef() - && (ti.bare_equal(user_type()) - || ti.bare_equal(bv.get_type_info()) - || dynamic_cast_converts(ti, bv.get_type_info()) - || bv.get_type_info().bare_equal(user_type >()) - ) - ) - ) - { - return true; - } else { - return false; - } - } - - bool compare_types(const std::vector &tis, const std::vector &bvs) const - { - if (tis.size() - 1 != bvs.size()) - { - return false; - } else { - size_t size = bvs.size(); - for (size_t i = 0; i < size; ++i) + if (tis.size() - 1 != bvs.size()) { - if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() )) + return false; + } else { + size_t size = bvs.size(); + for (size_t i = 0; i < size; ++i) { - return false; + if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() )) + { + return false; + } } } + return true; } - return true; - } - std::vector m_types; - }; + std::vector m_types; + }; + } - typedef boost::shared_ptr Proxy_Function; - typedef boost::shared_ptr Const_Proxy_Function; + typedef boost::shared_ptr Proxy_Function; + typedef boost::shared_ptr Const_Proxy_Function; namespace exception { @@ -192,444 +195,455 @@ namespace chaiscript }; } - /** - * A Proxy_Function implementation that is not type safe, the called function - * is expecting a vector that it works with how it chooses. - */ - class Dynamic_Proxy_Function : public Proxy_Function_Base + namespace dispatch { - public: - Dynamic_Proxy_Function( - const boost::function &)> &t_f, - int t_arity=-1, - const AST_NodePtr &t_parsenode = AST_NodePtr(), - const std::string &t_description = "", - const Proxy_Function &t_guard = Proxy_Function()) - : Proxy_Function_Base(build_param_type_list(t_arity)), + /** + * A Proxy_Function implementation that is not type safe, the called function + * is expecting a vector that it works with how it chooses. + */ + class Dynamic_Proxy_Function : public Proxy_Function_Base + { + public: + Dynamic_Proxy_Function( + const boost::function &)> &t_f, + int t_arity=-1, + const AST_NodePtr &t_parsenode = AST_NodePtr(), + const std::string &t_description = "", + const Proxy_Function &t_guard = Proxy_Function()) + : Proxy_Function_Base(build_param_type_list(t_arity)), m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode) { } - virtual bool operator==(const Proxy_Function_Base &rhs) const - { - return this == &rhs; - } + virtual bool operator==(const Proxy_Function_Base &rhs) const + { + return this == &rhs; + } - virtual bool call_match(const std::vector &vals) const - { + virtual bool call_match(const std::vector &vals) const + { return (m_arity < 0 || vals.size() == size_t(m_arity)) && test_guard(vals); - } + } - virtual ~Dynamic_Proxy_Function() {} + virtual ~Dynamic_Proxy_Function() {} - virtual int get_arity() const - { - return m_arity; - } - - Proxy_Function get_guard() const - { - return m_guard; - } - - AST_NodePtr get_parse_tree() const - { - return m_parsenode; - } - - virtual std::string annotation() const - { - return m_description; - } - - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - if (m_arity < 0 || params.size() == size_t(m_arity)) + virtual int get_arity() const { + return m_arity; + } - if (test_guard(params)) + Proxy_Function get_guard() const + { + return m_guard; + } + + AST_NodePtr get_parse_tree() const + { + return m_parsenode; + } + + virtual std::string annotation() const + { + return m_description; + } + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + if (m_arity < 0 || params.size() == size_t(m_arity)) { - return m_f(params); + + if (test_guard(params)) + { + return m_f(params); + } else { + throw exception::guard_error(); + } + } else { - throw exception::guard_error(); - } - - } else { - throw exception::arity_error(static_cast(params.size()), m_arity); - } - } - - private: - bool test_guard(const std::vector ¶ms) const - { - if (m_guard) - { - try { - return boxed_cast((*m_guard)(params)); - } catch (const exception::arity_error &) { - return false; - } catch (const exception::bad_boxed_cast &) { - return false; - } - } else { - return true; - } - } - - static std::vector build_param_type_list(int arity) - { - std::vector types; - - // For the return type - types.push_back(detail::Get_Type_Info::get()); - - if (arity >= 0) - { - for (int i = 0; i < arity; ++i) - { - types.push_back(detail::Get_Type_Info::get()); - } - } - - return types; - } - - boost::function &)> m_f; - int m_arity; - std::string m_description; - Proxy_Function m_guard; - AST_NodePtr m_parsenode; - }; - - /** - * An object used by Bound_Function to represent "_" parameters - * of a binding. This allows for unbound parameters during bind. - */ - struct Placeholder_Object - { - }; - - /** - * An implementation of Proxy_Function that takes a Proxy_Function - * and substitutes bound parameters into the parameter list - * at runtime, when call() is executed. - * it is used for bind(function, param1, _, param2) style calls - */ - class Bound_Function : public Proxy_Function_Base - { - public: - Bound_Function(const Const_Proxy_Function &t_f, - const std::vector &t_args) - : Proxy_Function_Base(build_param_type_info(t_f, t_args)), - m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:get_param_types().size()-1) - { - assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); - } - - virtual bool operator==(const Proxy_Function_Base &t_f) const - { - return &t_f == this; - } - - virtual ~Bound_Function() {} - - virtual bool call_match(const std::vector &vals) const - { - return m_f->call_match(build_param_list(vals)); - } - - virtual Boxed_Value operator()(const std::vector ¶ms) const - { - return (*m_f)(build_param_list(params)); - } - - virtual std::vector get_contained_functions() const - { - std::vector fs; - fs.push_back(m_f); - return fs; - } - - - std::vector build_param_list(const std::vector ¶ms) const - { - typedef std::vector::const_iterator pitr; - - pitr parg = params.begin(); - pitr barg = m_args.begin(); - - std::vector args; - - while (!(parg == params.end() && barg == m_args.end())) - { - while (barg != m_args.end() - && !(barg->get_type_info() == detail::Get_Type_Info::get())) - { - args.push_back(*barg); - ++barg; - } - - if (parg != params.end()) - { - args.push_back(*parg); - ++parg; - } - - if (barg != m_args.end() - && barg->get_type_info() == detail::Get_Type_Info::get()) - { - ++barg; + throw exception::arity_error(static_cast(params.size()), m_arity); } } - return args; - } - virtual int get_arity() const - { - return m_arity; - } - - virtual std::string annotation() const - { - return "Bound: " + m_f->annotation(); - } - - protected: - static std::vector build_param_type_info(const Const_Proxy_Function &t_f, - const std::vector &t_args) - { - assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); - if (t_f->get_arity() < 0) { return std::vector(); } - - std::vector types = t_f->get_param_types(); - assert(types.size() == t_args.size() + 1); - - std::vector retval; - retval.push_back(types[0]); - for (size_t i = 0; i < types.size()-1; ++i) + private: + bool test_guard(const std::vector ¶ms) const { - if (t_args[i].get_type_info() == detail::Get_Type_Info::get()) + if (m_guard) { - retval.push_back(types[i+1]); + try { + return boxed_cast((*m_guard)(params)); + } catch (const exception::arity_error &) { + return false; + } catch (const exception::bad_boxed_cast &) { + return false; + } + } else { + return true; } } - return retval; - } + static std::vector build_param_type_list(int arity) + { + std::vector types; - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - return (*m_f)(build_param_list(params)); - } + // For the return type + types.push_back(detail::Get_Type_Info::get()); - private: - Const_Proxy_Function m_f; - std::vector m_args; - int m_arity; - }; + if (arity >= 0) + { + for (int i = 0; i < arity; ++i) + { + types.push_back(detail::Get_Type_Info::get()); + } + } - /** - * The standard typesafe function call implementation of Proxy_Function - * It takes a boost::function<> object and performs runtime - * type checking of Boxed_Value parameters, in a type safe manner - */ - template - class Proxy_Function_Impl : public Proxy_Function_Base - { - public: - Proxy_Function_Impl(const boost::function &f) - : Proxy_Function_Base(detail::build_param_type_list(static_cast(0))), + return types; + } + + boost::function &)> m_f; + int m_arity; + std::string m_description; + Proxy_Function m_guard; + AST_NodePtr m_parsenode; + }; + + /** + * An object used by Bound_Function to represent "_" parameters + * of a binding. This allows for unbound parameters during bind. + */ + struct Placeholder_Object + { + }; + + /** + * An implementation of Proxy_Function that takes a Proxy_Function + * and substitutes bound parameters into the parameter list + * at runtime, when call() is executed. + * it is used for bind(function, param1, _, param2) style calls + */ + class Bound_Function : public Proxy_Function_Base + { + public: + Bound_Function(const Const_Proxy_Function &t_f, + const std::vector &t_args) + : Proxy_Function_Base(build_param_type_info(t_f, t_args)), + m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast(get_param_types().size())-1) + { + assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); + } + + virtual bool operator==(const Proxy_Function_Base &t_f) const + { + return &t_f == this; + } + + virtual ~Bound_Function() {} + + virtual bool call_match(const std::vector &vals) const + { + return m_f->call_match(build_param_list(vals)); + } + + virtual Boxed_Value operator()(const std::vector ¶ms) const + { + return (*m_f)(build_param_list(params)); + } + + virtual std::vector get_contained_functions() const + { + std::vector fs; + fs.push_back(m_f); + return fs; + } + + + std::vector build_param_list(const std::vector ¶ms) const + { + typedef std::vector::const_iterator pitr; + + pitr parg = params.begin(); + pitr barg = m_args.begin(); + + std::vector args; + + while (!(parg == params.end() && barg == m_args.end())) + { + while (barg != m_args.end() + && !(barg->get_type_info() == detail::Get_Type_Info::get())) + { + args.push_back(*barg); + ++barg; + } + + if (parg != params.end()) + { + args.push_back(*parg); + ++parg; + } + + if (barg != m_args.end() + && barg->get_type_info() == detail::Get_Type_Info::get()) + { + ++barg; + } + } + return args; + } + + virtual int get_arity() const + { + return m_arity; + } + + virtual std::string annotation() const + { + return "Bound: " + m_f->annotation(); + } + + protected: + static std::vector build_param_type_info(const Const_Proxy_Function &t_f, + const std::vector &t_args) + { + assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); + if (t_f->get_arity() < 0) { return std::vector(); } + + std::vector types = t_f->get_param_types(); + assert(types.size() == t_args.size() + 1); + + std::vector retval; + retval.push_back(types[0]); + for (size_t i = 0; i < types.size()-1; ++i) + { + if (t_args[i].get_type_info() == detail::Get_Type_Info::get()) + { + retval.push_back(types[i+1]); + } + } + + return retval; + } + + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + return (*m_f)(build_param_list(params)); + } + + private: + Const_Proxy_Function m_f; + std::vector m_args; + int m_arity; + }; + + /** + * The standard typesafe function call implementation of Proxy_Function + * It takes a boost::function<> object and performs runtime + * type checking of Boxed_Value parameters, in a type safe manner + */ + template + class Proxy_Function_Impl : public Proxy_Function_Base + { + public: + Proxy_Function_Impl(const boost::function &f) + : Proxy_Function_Base(detail::build_param_type_list(static_cast(0))), m_f(f), m_dummy_func(0) { } - virtual ~Proxy_Function_Impl() {} + virtual ~Proxy_Function_Impl() {} - virtual bool operator==(const Proxy_Function_Base &t_func) const - { - const Proxy_Function_Impl *pimpl = dynamic_cast *>(&t_func); - return pimpl != 0; - } - - - virtual int get_arity() const - { - return static_cast(m_types.size()) - 1; - } - - - virtual bool call_match(const std::vector &vals) const - { - if (int(vals.size()) != get_arity()) + virtual bool operator==(const Proxy_Function_Base &t_func) const { - return false; + const Proxy_Function_Impl *pimpl = dynamic_cast *>(&t_func); + return pimpl != 0; } - return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals); - } - virtual std::string annotation() const - { - return ""; - } + virtual int get_arity() const + { + return static_cast(m_types.size()) - 1; + } - boost::function internal_function() const - { - return m_f; - } - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - return detail::Do_Call::result_type>::go(m_f, params); - } + virtual bool call_match(const std::vector &vals) const + { + if (int(vals.size()) != get_arity()) + { + return false; + } - private: - boost::function m_f; - Func *m_dummy_func; - }; + return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals); + } - /** - * Attribute getter Proxy_Function implementation - */ - template - class Attribute_Access : public Proxy_Function_Base - { - public: - Attribute_Access(T Class::* t_attr) - : Proxy_Function_Base(param_types()), + virtual std::string annotation() const + { + return ""; + } + + boost::function internal_function() const + { + return m_f; + } + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + return detail::Do_Call::result_type>::go(m_f, params); + } + + private: + boost::function m_f; + Func *m_dummy_func; + }; + + /** + * Attribute getter Proxy_Function implementation + */ + template + class Attribute_Access : public Proxy_Function_Base + { + public: + Attribute_Access(T Class::* t_attr) + : Proxy_Function_Base(param_types()), m_attr(t_attr) { } - virtual ~Attribute_Access() {} + virtual ~Attribute_Access() {} - virtual bool operator==(const Proxy_Function_Base &t_func) const - { - const Attribute_Access * aa - = dynamic_cast *>(&t_func); - if (aa) { - return m_attr == aa->m_attr; - } else { - return false; - } - } - - - virtual int get_arity() const - { - return 1; - } - - virtual bool call_match(const std::vector &vals) const - { - if (vals.size() != 1) + virtual bool operator==(const Proxy_Function_Base &t_func) const { - return false; - } - - return vals[0].get_type_info().bare_equal(user_type()); - } - - virtual std::string annotation() const - { - return ""; - } - - protected: - virtual Boxed_Value do_call(const std::vector ¶ms) const - { - if (params.size() == 1) - { - const Boxed_Value &bv = params[0]; - if (bv.is_const()) - { - const Class *o = boxed_cast(bv); - return detail::Handle_Return::type>::handle(o->*m_attr); + const Attribute_Access * aa + = dynamic_cast *>(&t_func); + if (aa) { + return m_attr == aa->m_attr; } else { - Class *o = boxed_cast(bv); - return detail::Handle_Return::type>::handle(o->*m_attr); + return false; } - } else { - throw exception::arity_error(static_cast(params.size()), 1); - } - } - - private: - static std::vector param_types() - { - std::vector v; - v.push_back(user_type()); - v.push_back(user_type()); - return v; - } - T Class::* m_attr; - }; - - /** - * 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 dispatch_error : std::runtime_error - { - dispatch_error() throw() - : std::runtime_error("No matching function to dispatch to") - { - } - - dispatch_error(bool is_const) throw() - : std::runtime_error(std::string("No matching function to dispatch to") + (is_const?", parameter is const":"")) - { - } - - virtual ~dispatch_error() throw() {} - }; - - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(InItr begin, InItr end, - const std::vector &plist) - { - while (begin != end) - { - try { - if ((*begin)->filter(plist)) - { - return (*(*begin))(plist); } - } catch (const exception::bad_boxed_cast &) { - //parameter failed to cast, try again - } catch (const exception::arity_error &) { - //invalid num params, try again - } catch (const exception::guard_error &) { - //guard failed to allow the function to execute, - //try again - } - ++begin; - } - throw dispatch_error(plist.empty()?false:plist[0].is_const()); + + virtual int get_arity() const + { + return 1; + } + + virtual bool call_match(const std::vector &vals) const + { + if (vals.size() != 1) + { + return false; + } + + return vals[0].get_type_info().bare_equal(user_type()); + } + + virtual std::string annotation() const + { + return ""; + } + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms) const + { + if (params.size() == 1) + { + const Boxed_Value &bv = params[0]; + if (bv.is_const()) + { + const Class *o = boxed_cast(bv); + return detail::Handle_Return::type>::handle(o->*m_attr); + } else { + Class *o = boxed_cast(bv); + return detail::Handle_Return::type>::handle(o->*m_attr); + } + } else { + throw exception::arity_error(static_cast(params.size()), 1); + } + } + + private: + static std::vector param_types() + { + std::vector v; + v.push_back(user_type()); + v.push_back(user_type()); + return v; + } + T Class::* m_attr; + }; } - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist) + namespace exception { - return dispatch(funcs.begin(), funcs.end(), plist); + /** + * 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 + */ + class dispatch_error : public std::runtime_error + { + public: + dispatch_error() throw() + : std::runtime_error("No matching function to dispatch to") + { + } + + dispatch_error(bool is_const) throw() + : std::runtime_error(std::string("No matching function to dispatch to") + (is_const?", parameter is const":"")) + { + } + + virtual ~dispatch_error() throw() {} + }; + } + + namespace dispatch + { + + /** + * Take a vector of functions and a vector of parameters. Attempt to execute + * each function against the set of parameters, in order, until a matching + * function is found or throw dispatch_error if no matching function is found + */ + template + Boxed_Value dispatch(InItr begin, InItr end, + const std::vector &plist) + { + while (begin != end) + { + try { + if ((*begin)->filter(plist)) + { + return (*(*begin))(plist); + } + } catch (const exception::bad_boxed_cast &) { + //parameter failed to cast, try again + } catch (const exception::arity_error &) { + //invalid num params, try again + } catch (const exception::guard_error &) { + //guard failed to allow the function to execute, + //try again + } + ++begin; + } + + throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); + } + + /** + * Take a vector of functions and a vector of parameters. Attempt to execute + * each function against the set of parameters, in order, until a matching + * function is found or throw dispatch_error if no matching function is found + */ + template + Boxed_Value dispatch(const Funcs &funcs, + const std::vector &plist) + { + return dispatch::dispatch(funcs.begin(), funcs.end(), plist); + } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 7b426169..8402959b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -49,29 +49,6 @@ namespace chaiscript }; } - namespace detail - { - template - struct Do_Call - { - template - static Boxed_Value go(const boost::function &fun, const std::vector ¶ms) - { - return Handle_Return::handle(call_func(fun, params)); - } - }; - - template<> - struct Do_Call - { - template - static Boxed_Value go(const boost::function &fun, const std::vector ¶ms) - { - call_func(fun, params); - return Handle_Return::handle(); - } - }; - } } #define BOOST_PP_ITERATION_LIMITS ( 0, 10 ) @@ -143,3 +120,35 @@ namespace chaiscript #undef n #endif + + +#ifndef BOOST_PP_IS_ITERATING + +namespace chaiscript +{ + namespace detail + { + template + struct Do_Call + { + template + static Boxed_Value go(const boost::function &fun, const std::vector ¶ms) + { + return Handle_Return::handle(chaiscript::detail::call_func(fun, params)); + } + }; + + template<> + struct Do_Call + { + template + static Boxed_Value go(const boost::function &fun, const std::vector ¶ms) + { + chaiscript::detail::call_func(fun, params); + return Handle_Return::handle(); + } + }; + } +} + +#endif diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 6fa2bb4f..8db81134 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -18,61 +18,63 @@ namespace chaiscript { - namespace detail + namespace dispatch { - template - struct Fun_Helper - { - template - static Proxy_Function go(T t) + namespace detail + { + template + struct Fun_Helper { - return Proxy_Function( - new Proxy_Function_Impl< + template + static Proxy_Function go(T t) + { + return Proxy_Function( + new Proxy_Function_Impl< typename boost::function_types::function_type >::type> ( boost::function< - typename boost::function_types::function_type >::type - >(t))); - } - }; + typename boost::function_types::function_type >::type + >(t))); + } + }; - template<> - struct Fun_Helper - { - template - static Proxy_Function go(T t) + template<> + struct Fun_Helper { - return Proxy_Function( - new Proxy_Function_Impl< + template + static Proxy_Function go(T t) + { + return Proxy_Function( + new Proxy_Function_Impl< typename boost::function_types::function_type >::type> ( boost::function< - typename boost::function_types::function_type >::type + typename boost::function_types::function_type >::type >(boost::mem_fn(t)))); - } - }; + } + }; - template<> - struct Fun_Helper - { - template - static Proxy_Function go(T Class::* m) - { - return Proxy_Function(new Attribute_Access(m)); - } - }; - + template<> + struct Fun_Helper + { + template + static Proxy_Function go(T Class::* m) + { + return Proxy_Function(new Attribute_Access(m)); + } + }; + } } template Proxy_Function fun(const boost::function &f) { - return Proxy_Function(new Proxy_Function_Impl(f)); + return Proxy_Function(new dispatch::Proxy_Function_Impl(f)); } template Proxy_Function fun(T t) { - return detail::Fun_Helper::value, boost::function_types::is_member_function_pointer::value>::go(t); + return dispatch::detail::Fun_Helper::value, boost::function_types::is_member_function_pointer::value>::go(t); } template diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 15a224a1..733d926e 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -22,12 +22,14 @@ namespace chaiscript { - template - struct Bare_Type - { - typedef typename boost::remove_const::type>::type>::type type; - }; - + namespace detail + { + template + struct Bare_Type + { + typedef typename boost::remove_const::type>::type>::type type; + }; + } /** * compile time deduced information about a type diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index be6c9662..124b0528 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -8,6 +8,7 @@ #define CHAISCRIPT_COMMON_HPP_ #include +#include namespace chaiscript { @@ -57,110 +58,155 @@ namespace chaiscript typedef boost::shared_ptr AST_NodePtr; + namespace exception + { + /** + * Errors generated during parsing or evaluation + */ + struct eval_error : public std::runtime_error { + std::string reason; + File_Position start_position; + File_Position end_position; + std::string filename; + std::vector call_stack; + + eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) throw() : + std::runtime_error("Error: \"" + t_why + "\" " + + (t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + + + "at (" + boost::lexical_cast(t_where.line) + ", " + + boost::lexical_cast(t_where.column) + ")"), + reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) + { } + + eval_error(const std::string &t_why) throw() + : std::runtime_error("Error: \"" + t_why + "\" "), + reason(t_why) + {} + + virtual ~eval_error() throw() {} + }; + + /** + * Errors generated when loading a file + */ + struct file_not_found_error : public std::runtime_error { + file_not_found_error(const std::string &t_filename) throw() + : std::runtime_error("File Not Found: " + t_filename) + { } + + virtual ~file_not_found_error() throw() {} + }; + + } + /** * The struct that doubles as both a parser ast_node and an AST node */ - struct AST_Node { - std::string text; - int identifier; - boost::shared_ptr filename; - File_Position start, end; - std::vector children; - AST_NodePtr annotation; + struct AST_Node : boost::enable_shared_from_this { + public: + const std::string text; + const int identifier; + boost::shared_ptr filename; + File_Position start, end; + std::vector children; + AST_NodePtr annotation; - AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr &t_fname, - int t_start_line, int t_start_col, int t_end_line, int t_end_col) : - text(t_ast_node_text), identifier(t_id), filename(t_fname), - start(t_start_line, t_start_col), end(t_end_line, t_end_col) - { - } + /** + * Prints the contents of an AST node, including its children, recursively + */ + std::string to_string(std::string t_prepend = "") { + std::ostringstream oss; - AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr &t_fname) : - text(t_ast_node_text), identifier(t_id), filename(t_fname) {} - - virtual ~AST_Node() {} - - /** - * Prints the contents of an AST node, including its children, recursively - */ - std::string to_string(std::string t_prepend = "") { - std::ostringstream oss; - - oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " - << this->text << " : " << this->start.line << ", " << this->start.column << std::endl; - - for (unsigned int j = 0; j < this->children.size(); ++j) { - oss << this->children[j]->to_string(t_prepend + " "); + oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " + << this->text << " : " << this->start.line << ", " << this->start.column << std::endl; + + for (unsigned int j = 0; j < this->children.size(); ++j) { + oss << this->children[j]->to_string(t_prepend + " "); + } + return oss.str(); } - return oss.str(); - } - std::string internal_to_string() { - return to_string(); - } + std::string internal_to_string() { + return to_string(); + } - virtual Boxed_Value eval(Dispatch_Engine &) { - Boxed_Value bv; - throw std::runtime_error("Undispatched ast_node (internal error)"); - } + Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) + { + try { + return eval_internal(t_e); + } catch (exception::eval_error &ee) { + ee.call_stack.push_back(shared_from_this()); + throw ee; + } + } + + + void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child) + { + std::replace(children.begin(), children.end(), t_child, t_new_child); + } + + protected: + AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr &t_fname, + int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + text(t_ast_node_text), identifier(t_id), filename(t_fname), + start(t_start_line, t_start_col), end(t_end_line, t_end_col) + { + } + + AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr &t_fname) : + text(t_ast_node_text), identifier(t_id), filename(t_fname) {} + + virtual ~AST_Node() {} + + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) + { + throw std::runtime_error("Undispatched ast_node (internal error)"); + } }; - /** - * Errors generated during parsing or evaluation - */ - struct Eval_Error : public std::runtime_error { - std::string reason; - File_Position start_position; - File_Position end_position; - std::string filename; - std::vector call_stack; - Eval_Error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) : - std::runtime_error("Error: \"" + t_why + "\" " + - (t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + - + "at (" + boost::lexical_cast(t_where.line) + ", " + - boost::lexical_cast(t_where.column) + ")"), - reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) - { } + namespace detail + { + /** + * Special type for returned values + */ + struct Return_Value { + Boxed_Value retval; - Eval_Error(const std::string &t_why) - : std::runtime_error("Error: \"" + t_why + "\" "), - reason(t_why) - {} + Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } + }; - virtual ~Eval_Error() throw() {} - }; + /** + * Special type indicating a call to 'break' + */ + struct Break_Loop { + Break_Loop() { } + }; - /** - * Errors generated when loading a file - */ - struct File_Not_Found_Error : public std::runtime_error { - File_Not_Found_Error(const std::string &t_filename) - : std::runtime_error("File Not Found: " + t_filename) - { } + /// Creates a new scope then pops it on destruction + struct Scope_Push_Pop + { + Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) + : m_de(t_de) + { + m_de.new_scope(); + } - virtual ~File_Not_Found_Error() throw() {} - }; + ~Scope_Push_Pop() + { + m_de.pop_scope(); + } - /** - * Special type for returned values - */ - struct Return_Value { - Boxed_Value retval; + private: + chaiscript::detail::Dispatch_Engine &m_de; + }; - Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } - }; - - /** - * Special type indicating a call to 'break' - */ - struct Break_Loop { - Break_Loop() { } - }; + } } #endif /* _CHAISCRIPT_COMMON_HPP */ diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index f95eab45..309bef2d 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -28,205 +28,210 @@ namespace chaiscript { - struct load_module_error : std::runtime_error + namespace exception { - load_module_error(const std::string &t_reason) throw() - : std::runtime_error(t_reason) + struct load_module_error : std::runtime_error { - } + load_module_error(const std::string &t_reason) throw() + : std::runtime_error(t_reason) + { + } - virtual ~load_module_error() throw() - { - } - }; + virtual ~load_module_error() throw() + { + } + }; + } + namespace detail + { #ifdef _POSIX_VERSION - struct Loadable_Module - { - struct DLModule + struct Loadable_Module { - DLModule(const std::string &t_filename) - : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) + struct DLModule { - if (!m_data) + DLModule(const std::string &t_filename) + : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) + { + if (!m_data) { - throw load_module_error(dlerror()); + throw exception::load_module_error(dlerror()); } - } + } - DLModule(const DLModule &); // Explicitly unimplemented copy constructor - DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator + DLModule(const DLModule &); // Explicitly unimplemented copy constructor + DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator - ~DLModule() - { - dlclose(m_data); - } + ~DLModule() + { + dlclose(m_data); + } - void *m_data; - }; + void *m_data; + }; - template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) + template + struct DLSym + { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) { - throw load_module_error(dlerror()); + if (!m_symbol) + { + throw exception::load_module_error(dlerror()); + } } - } - T m_symbol; - }; + T m_symbol; + }; - Loadable_Module(const std::string &t_module_name, const std::string &t_filename) - : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), + Loadable_Module(const std::string &t_module_name, const std::string &t_filename) + : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), m_moduleptr(m_func.m_symbol()) - { - } + { + } - DLModule m_dlmodule; - DLSym m_func; - ModulePtr m_moduleptr; - }; + DLModule m_dlmodule; + DLSym m_func; + ModulePtr m_moduleptr; + }; #else #ifdef WIN32 - struct Loadable_Module - { - template - static std::wstring towstring(const T &t_str) + struct Loadable_Module { - return std::wstring(t_str.begin(), t_str.end()); - } + template + static std::wstring towstring(const T &t_str) + { + return std::wstring(t_str.begin(), t_str.end()); + } - template - static std::string tostring(const T &t_str) - { - return std::string(t_str.begin(), t_str.end()); - } + template + static std::string tostring(const T &t_str) + { + return std::string(t_str.begin(), t_str.end()); + } #ifdef _UNICODE - template - static std::wstring toproperstring(const T &t_str) - { - return towstring(t_str); - } + template + static std::wstring toproperstring(const T &t_str) + { + return towstring(t_str); + } #else - template - static std::string toproperstring(const T &t_str) - { - return tostring(t_str); - } + template + static std::string toproperstring(const T &t_str) + { + return tostring(t_str); + } #endif - static std::string GetErrorMessage(DWORD t_err) - { + static std::string GetErrorMessage(DWORD t_err) + { #ifdef _UNICODE - typedef LPWSTR StringType; - std::wstring retval = L"Unknown Error"; + typedef LPWSTR StringType; + std::wstring retval = L"Unknown Error"; #else - typedef LPSTR StringType; - std::string retval = "Unknown Error"; + typedef LPSTR StringType; + std::string retval = "Unknown Error"; #endif - StringType lpMsgBuf = 0; + StringType lpMsgBuf = 0; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - t_err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (StringType)&lpMsgBuf, - 0, NULL ); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + t_err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (StringType)&lpMsgBuf, + 0, NULL ); - if (lpMsgBuf) - { - retval = lpMsgBuf; + if (lpMsgBuf) + { + retval = lpMsgBuf; + } + + LocalFree(lpMsgBuf); + return tostring(retval); } - LocalFree(lpMsgBuf); - return tostring(retval); - } - - struct DLModule - { - DLModule(const std::string &t_filename) - : m_data(LoadLibrary(toproperstring(t_filename).c_str())) + struct DLModule { - if (!m_data) + DLModule(const std::string &t_filename) + : m_data(LoadLibrary(toproperstring(t_filename).c_str())) + { + if (!m_data) { - throw load_module_error(GetErrorMessage(GetLastError())); + throw exception::load_module_error(GetErrorMessage(GetLastError())); } - } + } - ~DLModule() - { - FreeLibrary(m_data); - } + ~DLModule() + { + FreeLibrary(m_data); + } - HMODULE m_data; - }; + HMODULE m_data; + }; - template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) + template + struct DLSym + { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) { - throw load_module_error(GetErrorMessage(GetLastError())); + if (!m_symbol) + { + throw exception::load_module_error(GetErrorMessage(GetLastError())); + } } - } - T m_symbol; - }; + T m_symbol; + }; - Loadable_Module(const std::string &t_module_name, const std::string &t_filename) - : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), + Loadable_Module(const std::string &t_module_name, const std::string &t_filename) + : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), m_moduleptr(m_func.m_symbol()) - { - } + { + } - DLModule m_dlmodule; - DLSym m_func; - ModulePtr m_moduleptr; - }; + DLModule m_dlmodule; + DLSym m_func; + ModulePtr m_moduleptr; + }; #else - struct Loadable_Module - { - Loadable_Module(const std::string &, const std::string &) + struct Loadable_Module { - throw load_module_error("Loadable module support not available for your platform"); - } + Loadable_Module(const std::string &, const std::string &) + { + throw exception::load_module_error("Loadable module support not available for your platform"); + } - ModulePtr m_moduleptr; - }; + ModulePtr m_moduleptr; + }; #endif #endif - typedef boost::shared_ptr Loadable_Module_Ptr; + typedef boost::shared_ptr Loadable_Module_Ptr; + } class ChaiScript { -#ifndef CHAISCRIPT_NO_THREADS - mutable boost::shared_mutex m_mutex; - mutable boost::recursive_mutex m_use_mutex; -#endif + + mutable chaiscript::detail::threading::shared_mutex m_mutex; + mutable chaiscript::detail::threading::recursive_mutex m_use_mutex; std::set m_used_files; - std::map m_loaded_modules; + std::map m_loaded_modules; std::set m_active_loaded_modules; std::vector m_modulepaths; std::vector m_usepaths; - Dispatch_Engine m_engine; + chaiscript::detail::Dispatch_Engine m_engine; /** @@ -235,7 +240,7 @@ namespace chaiscript Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) { try { - ChaiScript_Parser parser; + parser::ChaiScript_Parser parser; if (parser.parse(t_input, t_filename)) { //parser.show_match_stack(); return parser.ast()->eval(m_engine); @@ -243,7 +248,7 @@ namespace chaiscript return Boxed_Value(); } } - catch (const Return_Value &rv) { + catch (const detail::Return_Value &rv) { return rv.retval; } } @@ -271,23 +276,19 @@ namespace chaiscript try { const std::string appendedpath = m_usepaths[i] + t_filename; -#ifndef CHAISCRIPT_NO_THREADS - boost::lock_guard l(m_use_mutex); - boost::shared_lock l2(m_mutex); -#endif + chaiscript::detail::threading::lock_guard l(m_use_mutex); + chaiscript::detail::threading::shared_lock l2(m_mutex); if (m_used_files.count(appendedpath) == 0) { -#ifndef CHAISCRIPT_NO_THREADS m_used_files.insert(appendedpath); l2.unlock(); -#endif eval_file(appendedpath); } - } catch (const File_Not_Found_Error &) { + } catch (const exception::file_not_found_error &) { if (i == m_usepaths.size() - 1) { - throw File_Not_Found_Error(t_filename); + throw exception::file_not_found_error(t_filename); } // failed to load, try the next path @@ -295,6 +296,63 @@ namespace chaiscript } } + /** + * Returns the current evaluation m_engine + */ + chaiscript::detail::Dispatch_Engine &get_eval_engine() { + return m_engine; + } + + /** + * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. + */ + void build_eval_system() { + using namespace bootstrap; + m_engine.add_reserved_word("def"); + m_engine.add_reserved_word("fun"); + m_engine.add_reserved_word("while"); + m_engine.add_reserved_word("for"); + m_engine.add_reserved_word("if"); + m_engine.add_reserved_word("else"); + m_engine.add_reserved_word("&&"); + m_engine.add_reserved_word("||"); + m_engine.add_reserved_word(","); + m_engine.add_reserved_word(":="); + m_engine.add_reserved_word("var"); + m_engine.add_reserved_word("return"); + m_engine.add_reserved_word("break"); + m_engine.add_reserved_word("true"); + m_engine.add_reserved_word("false"); + m_engine.add_reserved_word("_"); + + add(Bootstrap::bootstrap()); + + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists"); + + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); + + + typedef void (ChaiScript::*load_mod_1)(const std::string&); + typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); + + m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); + m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); + + add(standard_library::vector_type >("Vector")); + add(standard_library::string_type("string")); + add(standard_library::map_type >("Map")); + add(standard_library::pair_type >("Pair")); + + m_engine.add(fun(&ChaiScript::use, this), "use"); + m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); + m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); + + do_eval(chaiscript_prelude, "standard prelude"); + } public: ChaiScript(const std::vector &t_modulepaths = std::vector(), @@ -326,7 +384,7 @@ namespace chaiscript struct State { std::set used_files; - Dispatch_Engine::State engine_state; + chaiscript::detail::Dispatch_Engine::State engine_state; std::set active_loaded_modules; }; @@ -337,10 +395,8 @@ namespace chaiscript */ State get_state() { -#ifndef CHAISCRIPT_NO_THREADS - boost::lock_guard l(m_use_mutex); - boost::shared_lock l2(m_mutex); -#endif + chaiscript::detail::threading::lock_guard l(m_use_mutex); + chaiscript::detail::threading::shared_lock l2(m_mutex); State s; s.used_files = m_used_files; @@ -354,10 +410,8 @@ namespace chaiscript */ void set_state(const State &t_state) { -#ifndef CHAISCRIPT_NO_THREADS - boost::lock_guard l(m_use_mutex); - boost::shared_lock l2(m_mutex); -#endif + chaiscript::detail::threading::lock_guard l(m_use_mutex); + chaiscript::detail::threading::shared_lock l2(m_mutex); m_used_files = t_state.used_files; m_active_loaded_modules = t_state.active_loaded_modules; @@ -388,7 +442,7 @@ namespace chaiscript */ void load_module(const std::string &t_module_name) { - std::vector errors; + std::vector errors; std::vector prefixes; prefixes.push_back("lib"); @@ -409,7 +463,7 @@ namespace chaiscript std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k]; load_module(t_module_name, name); return; - } catch (const load_module_error &e) { + } catch (const exception::load_module_error &e) { errors.push_back(e); // Try next set } @@ -419,7 +473,7 @@ namespace chaiscript std::string errstring; - for (std::vector::const_iterator itr = errors.begin(); + for (std::vector::const_iterator itr = errors.begin(); itr != errors.end(); ++itr) { @@ -431,7 +485,7 @@ namespace chaiscript errstring += itr->what(); } - throw load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring); + throw exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring); } /** @@ -439,13 +493,11 @@ namespace chaiscript */ void load_module(const std::string &t_module_name, const std::string &t_filename) { -#ifndef CHAISCRIPT_NO_THREADS - boost::lock_guard l(m_use_mutex); -#endif + chaiscript::detail::threading::lock_guard l(m_use_mutex); if (m_loaded_modules.count(t_module_name) == 0) { - Loadable_Module_Ptr lm(new Loadable_Module(t_module_name, t_filename)); + detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename)); m_loaded_modules[t_module_name] = lm; m_active_loaded_modules.insert(t_module_name); add(lm->m_moduleptr); @@ -456,19 +508,6 @@ namespace chaiscript } - /** - * Helper for calling script code as if it were native C++ code - * example: - * boost::function f = build_functor(chai, "func(x, y){x+y}"); - * \return a boost::function representing the passed in script - * \param[in] script Script code to build a function from - */ - template - boost::function functor(const std::string &t_script) - { - return chaiscript::functor(eval(t_script)); - } - /** * Evaluate a string via eval method */ @@ -478,13 +517,6 @@ namespace chaiscript } - /** - * Returns the current evaluation m_engine - */ - Dispatch_Engine &get_eval_engine() { - return m_engine; - } - /** * Helper function for loading a file */ @@ -492,7 +524,7 @@ namespace chaiscript std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); if (!infile.is_open()) { - throw File_Not_Found_Error(t_filename); + throw exception::file_not_found_error(t_filename); } std::streampos size = infile.tellg(); @@ -510,56 +542,6 @@ namespace chaiscript } } - /** - * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. - */ - void build_eval_system() { - using namespace bootstrap; - m_engine.add_reserved_word("def"); - m_engine.add_reserved_word("fun"); - m_engine.add_reserved_word("while"); - m_engine.add_reserved_word("for"); - m_engine.add_reserved_word("if"); - m_engine.add_reserved_word("else"); - m_engine.add_reserved_word("&&"); - m_engine.add_reserved_word("||"); - m_engine.add_reserved_word(","); - m_engine.add_reserved_word(":="); - m_engine.add_reserved_word("var"); - m_engine.add_reserved_word("return"); - m_engine.add_reserved_word("break"); - m_engine.add_reserved_word("true"); - m_engine.add_reserved_word("false"); - m_engine.add_reserved_word("_"); - - add(Bootstrap::bootstrap()); - - m_engine.add(fun(&Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system"); - m_engine.add(fun(&Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object"); - m_engine.add(fun(&Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type"); - m_engine.add(fun(&Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name"); - m_engine.add(fun(&Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists"); - - m_engine.add(fun(&Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); - - - typedef void (ChaiScript::*load_mod_1)(const std::string&); - typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); - - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); - - add(standard_library::vector_type >("Vector")); - add(standard_library::string_type("string")); - add(standard_library::map_type >("Map")); - add(standard_library::pair_type >("Pair")); - - m_engine.add(fun(&ChaiScript::use, this), "use"); - m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); - m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); - - do_eval(chaiscript_prelude, "standard prelude"); - } template T eval(const std::string &t_input) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 66655c39..b7609a7c 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -18,277 +18,252 @@ namespace chaiscript */ template const Boxed_Value eval_function (Eval_System &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals) { - t_ss.new_scope(); + detail::Scope_Push_Pop spp(t_ss); for (unsigned int i = 0; i < t_param_names.size(); ++i) { t_ss.add_object(t_param_names[i], t_vals[i]); } try { - Boxed_Value retval(t_node->eval(t_ss)); - t_ss.pop_scope(); - return retval; - } catch (const Return_Value &rv) { - t_ss.pop_scope(); + return t_node->eval(t_ss); + } catch (const detail::Return_Value &rv) { return rv.retval; - } catch (Eval_Error &ee) { - ee.call_stack.push_back(t_node); - t_ss.pop_scope(); - throw; - } catch (...) { - t_ss.pop_scope(); - throw; - } + } } - struct Binary_Operator_AST_Node : public AST_Node { - public: - Binary_Operator_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Binary_Operator_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; + namespace eval + { + struct Binary_Operator_AST_Node : public AST_Node { + public: + Binary_Operator_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Binary_Operator_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval; - try { retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } - for (size_t i = 1; i < this->children.size(); i += 2) { - try { - retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss)); - } - catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } - } - - return retval; - } - - }; - - struct Error_AST_Node : public AST_Node { - public: - Error_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Error, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - - virtual ~Error_AST_Node() {} - }; - - struct Int_AST_Node : public AST_Node { - public: - Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Int_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &){ - return const_var(int(atoi(this->text.c_str()))); - } - - }; - - struct Float_AST_Node : public AST_Node { - public: - Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Float_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &){ - return const_var(double(atof(this->text.c_str()))); - } - - }; - - struct Id_AST_Node : public AST_Node { - public: - Id_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Id, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Id_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - if (this->text == "true") { - return const_var(true); - } - else if (this->text == "false") { - return const_var(false); - } - else if (this->text == "Infinity") { - return const_var(std::numeric_limits::infinity()); - } - else if (this->text == "NaN") { - return const_var(std::numeric_limits::quiet_NaN()); - } - else { - try { - return t_ss.get_object(this->text); - } - catch (std::exception &) { - throw Eval_Error("Can not find object: " + this->text); - } - } - } - }; - - struct Char_AST_Node : public AST_Node { - public: - Char_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Char, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Char_AST_Node() {} - }; - - struct Str_AST_Node : public AST_Node { - public: - Str_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Str, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Str_AST_Node() {} - }; - - struct Eol_AST_Node : public AST_Node { - public: - Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Eol_AST_Node() {} - }; - - struct Fun_Call_AST_Node : public AST_Node { - public: - Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Fun_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Fun_Call_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Param_List_Builder plb; - - if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[1]->children.size(); ++i) { + for (size_t i = 1; i < this->children.size(); i += 2) { try { + retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss)); + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'"); + } + } + + return retval; + } + + }; + + struct Error_AST_Node : public AST_Node { + public: + Error_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Error, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + + virtual ~Error_AST_Node() {} + }; + + struct Int_AST_Node : public AST_Node { + public: + Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(const_var(int(atoi(this->text.c_str())))) { } + virtual ~Int_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + return m_value; + } + + private: + Boxed_Value m_value; + + }; + + struct Float_AST_Node : public AST_Node { + public: + Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(const_var(double(atof(this->text.c_str())))) { } + virtual ~Float_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + return m_value; + } + + private: + Boxed_Value m_value; + + }; + + struct Id_AST_Node : public AST_Node { + public: + Id_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Id, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(get_value(t_ast_node_text)) + { } + + virtual ~Id_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + if (!m_value.is_undef()) + { + return m_value; + } else { + try { + return t_ss.get_object(this->text); + } + catch (std::exception &) { + throw exception::eval_error("Can not find object: " + this->text); + } + } + } + + private: + static Boxed_Value get_value(const std::string &t_text) + { + if (t_text == "true") { + return const_var(true); + } + else if (t_text == "false") { + return const_var(false); + } + else if (t_text == "Infinity") { + return const_var(std::numeric_limits::infinity()); + } + else if (t_text == "NaN") { + return const_var(std::numeric_limits::quiet_NaN()); + } else { + return Boxed_Value(); + } + } + + Boxed_Value m_value; + }; + + struct Char_AST_Node : public AST_Node { + public: + Char_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Char, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Char_AST_Node() {} + }; + + struct Str_AST_Node : public AST_Node { + public: + Str_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Str, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Str_AST_Node() {} + }; + + struct Eol_AST_Node : public AST_Node { + public: + Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Eol_AST_Node() {} + }; + + struct Fun_Call_AST_Node : public AST_Node { + public: + Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Fun_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Fun_Call_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + dispatch::Param_List_Builder plb; + + if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { + for (size_t i = 0; i < this->children[1]->children.size(); ++i) { plb << this->children[1]->children[i]->eval(t_ss); } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); + } + + chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); + chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack(); + + try { + Boxed_Value fn = this->children[0]->eval(t_ss); + + try { + t_ss.set_stack(new_stack); + const Boxed_Value &retval = (*boxed_cast(fn))(plb); + t_ss.set_stack(prev_stack); + return retval; + } + catch(const exception::dispatch_error &e){ + t_ss.set_stack(prev_stack); + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } + catch(detail::Return_Value &rv) { + t_ss.set_stack(prev_stack); + return rv.retval; + } + catch(...) { + t_ss.set_stack(prev_stack); throw; } } - } - - Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - Dispatch_Engine::Stack new_stack = t_ss.new_stack(); - - try { - Boxed_Value fn = this->children[0]->eval(t_ss); - - try { - t_ss.set_stack(new_stack); - const Boxed_Value &retval = (*boxed_cast(fn))(plb); - t_ss.set_stack(prev_stack); - return retval; - } - catch(const dispatch_error &e){ - t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); - } - catch(Return_Value &rv) { - t_ss.set_stack(prev_stack); - return rv.retval; - } - catch(...) { + catch(exception::eval_error &ee) { t_ss.set_stack(prev_stack); throw; } - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - t_ss.set_stack(prev_stack); - throw Eval_Error(ee.reason); + } - } + }; - }; + struct Inplace_Fun_Call_AST_Node : public AST_Node { + public: + Inplace_Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inplace_Fun_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Inplace_Fun_Call_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + dispatch::Param_List_Builder plb; - struct Inplace_Fun_Call_AST_Node : public AST_Node { - public: - Inplace_Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inplace_Fun_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Inplace_Fun_Call_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Param_List_Builder plb; - - if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[1]->children.size(); ++i) { - try { + if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { + for (size_t i = 0; i < this->children[1]->children.size(); ++i) { plb << this->children[1]->children[i]->eval(t_ss); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); - throw; - } } - } - - try { - Boxed_Value fn = this->children[0]->eval(t_ss); try { - return (*boxed_cast(fn))(plb); + return (*boxed_cast(this->children[0]->eval(t_ss)))(plb); } - catch(const dispatch_error &e){ - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + catch(const exception::dispatch_error &e){ + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { return rv.retval; } catch(...) { throw; } } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw Eval_Error(ee.reason); - } - } + }; - }; + struct Arg_List_AST_Node : public AST_Node { + public: + Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Arg_List_AST_Node() {} + }; - struct Arg_List_AST_Node : public AST_Node { - public: - Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Arg_List_AST_Node() {} - }; + struct Variable_AST_Node : public AST_Node { + public: + Variable_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Variable, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Variable_AST_Node() {} + }; - struct Variable_AST_Node : public AST_Node { - public: - Variable_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Variable, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Variable_AST_Node() {} - }; + struct Equation_AST_Node : public AST_Node { + public: + Equation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equation, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Equation_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval = this->children.back()->eval(t_ss); - struct Equation_AST_Node : public AST_Node { - public: - Equation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equation, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Equation_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children.back()->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()); - throw; - } - - if (this->children.size() > 1) { - for (int i = static_cast(this->children.size())-3; i >= 0; i -= 2) { - if (this->children[i+1]->text == "=") { - try { + if (this->children.size() > 1) { + for (int i = static_cast(this->children.size())-3; i >= 0; i -= 2) { + if (this->children[i+1]->text == "=") { Boxed_Value lhs = this->children[i]->eval(t_ss); try { @@ -300,1215 +275,896 @@ namespace chaiscript try { retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); } - catch(const dispatch_error &){ - throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); + catch(const exception::dispatch_error &){ + throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); } } - catch(const dispatch_error &){ - throw Eval_Error("Can not clone right hand side of equation"); + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not clone right hand side of equation"); } } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } - } - else if (this->children[i+1]->text == ":=") { - try { + else if (this->children[i+1]->text == ":=") { Boxed_Value lhs = this->children[i]->eval(t_ss); if (lhs.is_undef() || type_match(lhs, retval)) { lhs.assign(retval); - } - else { - throw Eval_Error("Mismatched types in equation"); + } else { + throw exception::eval_error("Mismatched types in equation"); } } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } - } - else { - try { - retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); - } - catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i+1]->text + "'"); - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } - } - } - } - return retval; - } - }; - - struct Var_Decl_AST_Node : public AST_Node { - public: - Var_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Var_Decl, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Var_Decl_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - try { - t_ss.add_object(this->children[0]->text, Boxed_Value()); - } - catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as variable '" + this->children[0]->text + "'"); - } - return t_ss.get_object(this->children[0]->text); - } - - }; - - struct Comparison_AST_Node : public Binary_Operator_AST_Node { - public: - Comparison_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Comparison, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Comparison_AST_Node() {} - }; - - struct Additive_AST_Node : public Binary_Operator_AST_Node { - public: - Additive_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Additive, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Additive_AST_Node() {} - }; - - struct Multiplicative_AST_Node : public Binary_Operator_AST_Node { - public: - Multiplicative_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplicative, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Multiplicative_AST_Node() {} - }; - - struct Array_Call_AST_Node : public AST_Node { - public: - Array_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Array_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Array_Call_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - - try { - retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } - - for (size_t i = 1; i < this->children.size(); ++i) { - try { - retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); - } - catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception"); - } - catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } - } - - return retval; - } - }; - - struct Dot_Access_AST_Node : public AST_Node { - public: - Dot_Access_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Dot_Access, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Dot_Access_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } - - if (this->children.size() > 1) { - for (size_t i = 2; i < this->children.size(); i+=2) { - Param_List_Builder plb; - plb << retval; - - if (this->children[i]->children.size() > 1) { - for (size_t j = 0; j < this->children[i]->children[1]->children.size(); ++j) { + else { try { + retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); + } catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'"); + } + } + } + } + return retval; + } + }; + + struct Var_Decl_AST_Node : public AST_Node { + public: + Var_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Var_Decl, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Var_Decl_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + try { + t_ss.add_object(this->children[0]->text, Boxed_Value()); + } + catch (const exception::reserved_word_error &) { + throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); + } + return t_ss.get_object(this->children[0]->text); + } + + }; + + struct Comparison_AST_Node : public Binary_Operator_AST_Node { + public: + Comparison_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Comparison, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Comparison_AST_Node() {} + }; + + struct Additive_AST_Node : public Binary_Operator_AST_Node { + public: + Additive_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Additive, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Additive_AST_Node() {} + }; + + struct Multiplicative_AST_Node : public Binary_Operator_AST_Node { + public: + Multiplicative_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplicative, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Multiplicative_AST_Node() {} + }; + + struct Array_Call_AST_Node : public AST_Node { + public: + Array_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Array_Call, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Array_Call_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval = this->children[0]->eval(t_ss); + + for (size_t i = 1; i < this->children.size(); ++i) { + try { + retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); + } + catch(std::out_of_range &) { + throw exception::eval_error("Out of bounds exception"); + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate array lookup '[]' "); + } + } + + return retval; + } + }; + + struct Dot_Access_AST_Node : public AST_Node { + public: + Dot_Access_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Dot_Access, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Dot_Access_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval = this->children[0]->eval(t_ss); + + if (this->children.size() > 1) { + for (size_t i = 2; i < this->children.size(); i+=2) { + dispatch::Param_List_Builder plb; + plb << retval; + + if (this->children[i]->children.size() > 1) { + for (size_t j = 0; j < this->children[i]->children[1]->children.size(); ++j) { plb << this->children[i]->children[1]->children[j]->eval(t_ss); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]->children[1]->children[j]); - throw; - } } - } - std::string fun_name; - if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) { - fun_name = this->children[i]->children[0]->text; - } - else { - fun_name = this->children[i]->text; - } - - Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - Dispatch_Engine::Stack new_stack = t_ss.new_stack(); - - try { - t_ss.set_stack(new_stack); - retval = t_ss.call_function(fun_name, plb); - t_ss.set_stack(prev_stack); - } - catch(const dispatch_error &e){ - t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what())); - } - catch(Return_Value &rv) { - t_ss.set_stack(prev_stack); - retval = rv.retval; - } - catch(...) { - t_ss.set_stack(prev_stack); - throw; - } - if (this->children[i]->identifier == AST_Node_Type::Array_Call) { - for (size_t j = 1; j < this->children[i]->children.size(); ++j) { - try { - retval = t_ss.call_function("[]", retval, this->children[i]->children[j]->eval(t_ss)); - } - catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception"); - } - catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]->children[j]); - throw; - } + std::string fun_name; + if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) { + fun_name = this->children[i]->children[0]->text; } - } - } - } - - return retval; - } - - }; - - struct Quoted_String_AST_Node : public AST_Node { - public: - Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Quoted_String, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Quoted_String_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &){ - return const_var(this->text); - } - - }; - - struct Single_Quoted_String_AST_Node : public AST_Node { - public: - Single_Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Single_Quoted_String, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Single_Quoted_String_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &){ - return const_var(char(this->text[0])); - } - - }; - - struct Lambda_AST_Node : public AST_Node { - public: - Lambda_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Lambda, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Lambda_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - std::vector t_param_names; - size_t numparams = 0; - - if ((this->children.size() > 0) && (this->children[0]->identifier == AST_Node_Type::Arg_List)) { - numparams = this->children[0]->children.size(); - for (size_t i = 0; i < numparams; ++i) { - t_param_names.push_back(this->children[0]->children[i]->text); - } - - } - else { - //no parameters - numparams = 0; - } - - return Boxed_Value(Proxy_Function(new Dynamic_Proxy_Function - (boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), t_param_names, _1), - static_cast(numparams), this->children.back()))); - } - - }; - - struct Block_AST_Node : public AST_Node { - public: - Block_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Block, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Block_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - size_t num_children = this->children.size(); - - t_ss.new_scope(); - for (size_t i = 0; i < num_children; ++i) { - try { - const Boxed_Value &retval = this->children[i]->eval(t_ss); - - if (i + 1 == num_children) - { - t_ss.pop_scope(); - return retval; - } - } - catch (const chaiscript::Return_Value &) { - t_ss.pop_scope(); - throw; - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - t_ss.pop_scope(); - throw; - } - catch (...) { - t_ss.pop_scope(); - throw; - } - } - - t_ss.pop_scope(); - return Boxed_Value(); - } - - }; - - struct Def_AST_Node : public AST_Node { - public: - Def_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Def, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Def_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - std::vector t_param_names; - size_t numparams = 0; - AST_NodePtr guardnode; - - if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - numparams = this->children[1]->children.size(); - for (size_t i = 0; i < numparams; ++i) { - t_param_names.push_back(this->children[1]->children[i]->text); - } - - if (this->children.size() > 3) { - guardnode = this->children[2]; - } - } - else { - //no parameters - numparams = 0; - - if (this->children.size() > 2) { - guardnode = this->children[1]; - } - } - - boost::shared_ptr guard; - if (guardnode) { - guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(t_ss), guardnode, - t_param_names, _1), static_cast(numparams), guardnode)); - } - - try { - const std::string & l_function_name = this->children[0]->text; - const std::string & l_annotation = this->annotation?this->annotation->text:""; - t_ss.add(Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), this->children.back(), - l_annotation, guard)), l_function_name); - } - catch (reserved_word_error &e) { - throw Eval_Error("Reserved word used as function name '" + e.word + "'"); - } - return Boxed_Value(); - } - - }; - - struct While_AST_Node : public AST_Node { - public: - While_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::While, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~While_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - bool cond; - - t_ss.new_scope(); - - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); - throw; - } - while (cond) { - try { - try { - this->children[1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } - - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); - throw; - } - } - catch (Break_Loop &) { - cond = false; - } - } - t_ss.pop_scope(); - return Boxed_Value(); - } - ; - }; - - struct If_AST_Node : public AST_Node { - public: - If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~If_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - bool cond; - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (const exception::bad_boxed_cast &) { - throw Eval_Error("If condition not boolean"); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } - - if (cond) { - try { - return this->children[1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } - } - else { - if (this->children.size() > 2) { - size_t i = 2; - while ((!cond) && (i < this->children.size())) { - if (this->children[i]->text == "else") { - try { - return this->children[i+1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } + else { + fun_name = this->children[i]->text; } - else if (this->children[i]->text == "else if") { - try { - cond = boxed_cast(this->children[i+1]->eval(t_ss)); - } - catch (const exception::bad_boxed_cast &) { - throw Eval_Error("'else if' condition not boolean"); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } - if (cond) { + + chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); + chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack(); + + try { + t_ss.set_stack(new_stack); + retval = t_ss.call_function(fun_name, plb); + t_ss.set_stack(prev_stack); + } + catch(const exception::dispatch_error &e){ + t_ss.set_stack(prev_stack); + throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name); + } + catch(detail::Return_Value &rv) { + t_ss.set_stack(prev_stack); + retval = rv.retval; + } + catch(...) { + t_ss.set_stack(prev_stack); + throw; + } + if (this->children[i]->identifier == AST_Node_Type::Array_Call) { + for (size_t j = 1; j < this->children[i]->children.size(); ++j) { try { - return this->children[i+2]->eval(t_ss); + retval = t_ss.call_function("[]", retval, this->children[i]->children[j]->eval(t_ss)); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+2]); - throw; + catch(std::out_of_range &) { + throw exception::eval_error("Out of bounds exception"); + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate array lookup '[]' "); } } } - i = i + 3; } } + + return retval; } - return Boxed_Value(false); - } + }; - }; + struct Quoted_String_AST_Node : public AST_Node { + public: + Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Quoted_String, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(const_var(this->text)) { } + virtual ~Quoted_String_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) { + return m_value; + } - struct For_AST_Node : public AST_Node { - public: - For_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::For, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~For_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - bool cond; + private: + Boxed_Value m_value; - t_ss.new_scope(); + }; - try { - if (this->children.size() == 4) { - try { - this->children[0]->eval(t_ss); + struct Single_Quoted_String_AST_Node : public AST_Node { + public: + Single_Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Single_Quoted_String, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(const_var(char(this->text[0]))) { } + virtual ~Single_Quoted_String_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + return m_value; + } + + private: + Boxed_Value m_value; + }; + + struct Lambda_AST_Node : public AST_Node { + public: + Lambda_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Lambda, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Lambda_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + std::vector t_param_names; + size_t numparams = 0; + + if ((this->children.size() > 0) && (this->children[0]->identifier == AST_Node_Type::Arg_List)) { + numparams = this->children[0]->children.size(); + for (size_t i = 0; i < numparams; ++i) { + t_param_names.push_back(this->children[0]->children[i]->text); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); + + } + else { + //no parameters + numparams = 0; + } + + return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function + (boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), t_param_names, _1), + static_cast(numparams), this->children.back()))); + } + + }; + + struct Block_AST_Node : public AST_Node { + public: + Block_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Block, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Block_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + const size_t num_children = this->children.size(); + + detail::Scope_Push_Pop spp(t_ss); + + for (size_t i = 0; i < num_children; ++i) { + try { + const Boxed_Value &retval = this->children[i]->eval(t_ss); + + if (i + 1 == num_children) + { + return retval; + } + } + catch (const chaiscript::detail::Return_Value &) { throw; } + } - try { - cond = boxed_cast(this->children[1]->eval(t_ss)); + return Boxed_Value(); + } + + }; + + struct Def_AST_Node : public AST_Node { + public: + Def_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Def, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Def_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + std::vector t_param_names; + size_t numparams = 0; + AST_NodePtr guardnode; + + if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { + numparams = this->children[1]->children.size(); + for (size_t i = 0; i < numparams; ++i) { + t_param_names.push_back(this->children[1]->children[i]->text); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; + + if (this->children.size() > 3) { + guardnode = this->children[2]; } } else { - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); - throw; + //no parameters + numparams = 0; + + if (this->children.size() > 2) { + guardnode = this->children[1]; } } - } - catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); - } - while (cond) { + + boost::shared_ptr guard; + if (guardnode) { + guard = boost::shared_ptr + (new dispatch::Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(t_ss), guardnode, + t_param_names, _1), static_cast(numparams), guardnode)); + } + try { - if (this->children.size() == 4) { - try { - this->children[3]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[3]); - throw; - } + const std::string & l_function_name = this->children[0]->text; + const std::string & l_annotation = this->annotation?this->annotation->text:""; + t_ss.add(Proxy_Function + (new dispatch::Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(t_ss), this->children.back(), + t_param_names, _1), static_cast(numparams), this->children.back(), + l_annotation, guard)), l_function_name); + } + catch (const exception::reserved_word_error &e) { + throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); + } + return Boxed_Value(); + } - try { - this->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[2]); - throw; - } + }; - try { - cond = boxed_cast(this->children[1]->eval(t_ss)); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } - } - else { - try { - this->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[2]); - throw; - } + struct While_AST_Node : public AST_Node { + public: + While_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::While, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~While_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + bool cond; - try { - this->children[1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } + detail::Scope_Push_Pop spp(t_ss); + + try { + cond = boxed_cast(this->children[0]->eval(t_ss)); + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("While condition not boolean"); + } + while (cond) { + try { + this->children[1]->eval(t_ss); try { cond = boxed_cast(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); - throw; + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("While condition not boolean"); + } + } + catch (detail::Break_Loop &) { + cond = false; + } + } + return Boxed_Value(); + } + + }; + + struct If_AST_Node : public AST_Node { + public: + If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~If_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + bool cond; + try { + cond = boxed_cast(this->children[0]->eval(t_ss)); + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("If condition not boolean"); + } + + if (cond) { + return this->children[1]->eval(t_ss); + } + else { + if (this->children.size() > 2) { + size_t i = 2; + while ((!cond) && (i < this->children.size())) { + if (this->children[i]->text == "else") { + return this->children[i+1]->eval(t_ss); + } + else if (this->children[i]->text == "else if") { + try { + cond = boxed_cast(this->children[i+1]->eval(t_ss)); + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("'else if' condition not boolean"); + } + if (cond) { + return this->children[i+2]->eval(t_ss); + } + } + i = i + 3; } } } - catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); - } - catch (Break_Loop &) { - cond = false; - } + + return Boxed_Value(false); } - t_ss.pop_scope(); - return Boxed_Value(); - } - }; + }; - struct Inline_Array_AST_Node : public AST_Node { - public: - Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Inline_Array_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - std::vector vec; - if (this->children.size() > 0) { - for (size_t i = 0; i < this->children[0]->children.size(); ++i) { + struct For_AST_Node : public AST_Node { + public: + For_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::For, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~For_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + bool cond; + + detail::Scope_Push_Pop spp(t_ss); + + try { + if (this->children.size() == 4) { + this->children[0]->eval(t_ss); + + cond = boxed_cast(this->children[1]->eval(t_ss)); + } else { + cond = boxed_cast(this->children[0]->eval(t_ss)); + } + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("For condition not boolean"); + } + while (cond) { try { + if (this->children.size() == 4) { + this->children[3]->eval(t_ss); + this->children[2]->eval(t_ss); + + cond = boxed_cast(this->children[1]->eval(t_ss)); + } + else { + this->children[2]->eval(t_ss); + + this->children[1]->eval(t_ss); + + cond = boxed_cast(this->children[0]->eval(t_ss)); + } + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("For condition not boolean"); + } + catch (detail::Break_Loop &) { + cond = false; + } + } + return Boxed_Value(); + } + + }; + + struct Inline_Array_AST_Node : public AST_Node { + public: + Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Inline_Array_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + std::vector vec; + if (this->children.size() > 0) { + for (size_t i = 0; i < this->children[0]->children.size(); ++i) { vec.push_back(this->children[0]->children[i]->eval(t_ss)); } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]->children[i]); - throw; - } } + + return const_var(vec); } - return const_var(vec); - } + }; - }; - - struct Inline_Map_AST_Node : public AST_Node { - public: - Inline_Map_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Map, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Inline_Map_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - try { - std::map retval; - for (size_t i = 0; i < this->children[0]->children.size(); ++i) { - try { + struct Inline_Map_AST_Node : public AST_Node { + public: + Inline_Map_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Map, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Inline_Map_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + try { + std::map retval; + for (size_t i = 0; i < this->children[0]->children.size(); ++i) { retval[boxed_cast(this->children[0]->children[i]->children[0]->eval(t_ss))] = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss)); } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]->children[i]); - throw; - } + return const_var(retval); } - return const_var(retval); - } - catch (const dispatch_error &) { - throw Eval_Error("Can not find appropriate 'Map()'"); - } - } - - }; - - struct Return_AST_Node : public AST_Node { - public: - Return_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Return, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Return_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - if (this->children.size() > 0) { - try { - throw Return_Value(this->children[0]->eval(t_ss)); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; + catch (const exception::dispatch_error &) { + throw exception::eval_error("Can not find appropriate 'Map()'"); } } - else { - throw Return_Value(Boxed_Value()); + + }; + + struct Return_AST_Node : public AST_Node { + public: + Return_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Return, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Return_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + if (this->children.size() > 0) { + throw detail::Return_Value(this->children[0]->eval(t_ss)); + } + else { + throw detail::Return_Value(Boxed_Value()); + } } - } - }; + }; - struct File_AST_Node : public AST_Node { - public: - File_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::File, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~File_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss) { - const size_t size = this->children.size(); - for (size_t i = 0; i < size; ++i) { - try { + struct File_AST_Node : public AST_Node { + public: + File_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::File, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~File_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + const size_t size = this->children.size(); + for (size_t i = 0; i < size; ++i) { const Boxed_Value &retval = this->children[i]->eval(t_ss); if (i + 1 == size) { return retval; } } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } + return Boxed_Value(); } - return Boxed_Value(); - } - }; + }; - struct Prefix_AST_Node : public AST_Node { - public: - Prefix_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Prefix, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Prefix_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - try { + struct Prefix_AST_Node : public AST_Node { + public: + Prefix_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Prefix, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Prefix_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss)); } - catch(std::exception &){ - throw Eval_Error("Can not find appropriate unary '" + this->children[0]->text + "'"); + + }; + + struct Break_AST_Node : public AST_Node { + public: + Break_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Break, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Break_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + throw detail::Break_Loop(); } - } + }; - }; + struct Map_Pair_AST_Node : public AST_Node { + public: + Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Map_Pair_AST_Node() {} + }; - struct Break_AST_Node : public AST_Node { - public: - Break_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Break, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Break_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &){ - throw Break_Loop(); - } - }; + struct Value_Range_AST_Node : public AST_Node { + public: + Value_Range_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Value_Range, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Value_Range_AST_Node() {} + }; - struct Map_Pair_AST_Node : public AST_Node { - public: - Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Map_Pair_AST_Node() {} - }; - - struct Value_Range_AST_Node : public AST_Node { - public: - Value_Range_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Value_Range, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Value_Range_AST_Node() {} - }; - - struct Inline_Range_AST_Node : public AST_Node { - public: - Inline_Range_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Range, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Inline_Range_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - try { - return t_ss.call_function("generate_range", - this->children[0]->children[0]->children[0]->eval(t_ss), - this->children[0]->children[0]->children[1]->eval(t_ss)); - } - catch (const dispatch_error &) { - throw Eval_Error("Unable to generate range vector"); - } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]->children[0]); - throw; - } - } - - }; - - struct Annotation_AST_Node : public AST_Node { - public: - Annotation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Annotation, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Annotation_AST_Node() {} - }; - - struct Try_AST_Node : public AST_Node { - public: - Try_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Try, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Try_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - - t_ss.new_scope(); - try { - retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee2) { - ee2.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - t_ss.pop_scope(); - throw; - } - catch (const std::exception &e) { - Boxed_Value except = Boxed_Value(boost::ref(e)); - - size_t end_point = this->children.size(); - if (this->children.back()->identifier == AST_Node_Type::Finally) { - assert(end_point > 0); - end_point = this->children.size() - 1; - } - for (unsigned int i = 1; i < end_point; ++i) { - AST_NodePtr catch_block = this->children[i]; - - if (catch_block->children.size() == 1) { - //No variable capture, no guards - try { - retval = catch_block->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[0]); - throw; - } - break; - } - else if (catch_block->children.size() == 2) { - //Variable capture, no guards - t_ss.add_object(catch_block->children[0]->text, except); - try { - retval = catch_block->children[1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[1]); - throw; - } - - break; - } - else if (catch_block->children.size() == 3) { - //Variable capture, no guards - t_ss.add_object(catch_block->children[0]->text, except); - - bool guard; - try { - guard = boxed_cast(catch_block->children[1]->eval(t_ss)); - } catch (const exception::bad_boxed_cast &) { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); - } - if (guard) { - try { - retval = catch_block->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[2]); - throw; - } - - break; - } - } - else { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - t_ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized"); - } - } - } - catch (Boxed_Value &bv) { - Boxed_Value except = bv; - for (size_t i = 1; i < this->children.size(); ++i) { - AST_NodePtr catch_block = this->children[i]; - - if (catch_block->children.size() == 1) { - //No variable capture, no guards - try { - retval = catch_block->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[0]); - throw; - } - - break; - } - else if (catch_block->children.size() == 2) { - //Variable capture, no guards - t_ss.add_object(catch_block->children[0]->text, except); - try { - retval = catch_block->children[1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[1]); - throw; - } - - break; - } - else if (catch_block->children.size() == 3) { - //Variable capture, no guards - t_ss.add_object(catch_block->children[0]->text, except); - - bool guard; - try { - guard = boxed_cast(catch_block->children[1]->eval(t_ss)); - } - catch (const exception::bad_boxed_cast &) { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - - t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[1]); - throw; - } - if (guard) { - try { - retval = catch_block->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[2]); - throw; - } - break; - } - } - else { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - t_ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized"); - } - } - } - catch (...) { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); - throw; - } - } - t_ss.pop_scope(); - throw; - } - - if (this->children.back()->identifier == AST_Node_Type::Finally) { + struct Inline_Range_AST_Node : public AST_Node { + public: + Inline_Range_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Range, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Inline_Range_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ try { - retval = this->children.back()->children[0]->eval(t_ss); + return t_ss.call_function("generate_range", + this->children[0]->children[0]->children[0]->eval(t_ss), + this->children[0]->children[0]->children[1]->eval(t_ss)); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); + catch (const exception::dispatch_error &) { + throw exception::eval_error("Unable to generate range vector"); + } + } + + }; + + struct Annotation_AST_Node : public AST_Node { + public: + Annotation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Annotation, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Annotation_AST_Node() {} + }; + + struct Try_AST_Node : public AST_Node { + public: + Try_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Try, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Try_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval; + + detail::Scope_Push_Pop spp(t_ss); + + try { + retval = this->children[0]->eval(t_ss); + } + catch (exception::eval_error &ee) { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } throw; } - } + catch (const std::exception &e) { + Boxed_Value except = Boxed_Value(boost::ref(e)); - t_ss.pop_scope(); + size_t end_point = this->children.size(); + if (this->children.back()->identifier == AST_Node_Type::Finally) { + assert(end_point > 0); + end_point = this->children.size() - 1; + } + for (unsigned int i = 1; i < end_point; ++i) { + AST_NodePtr catch_block = this->children[i]; - return retval; - } + if (catch_block->children.size() == 1) { + //No variable capture, no guards + retval = catch_block->children[0]->eval(t_ss); + break; + } + else if (catch_block->children.size() == 2) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); + retval = catch_block->children[1]->eval(t_ss); - }; + break; + } + else if (catch_block->children.size() == 3) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); - struct Catch_AST_Node : public AST_Node { - public: - Catch_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Catch, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Catch_AST_Node() {} - }; + bool guard; + try { + guard = boxed_cast(catch_block->children[1]->eval(t_ss)); + } catch (const exception::bad_boxed_cast &) { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } + throw exception::eval_error("Guard condition not boolean"); + } + if (guard) { + retval = catch_block->children[2]->eval(t_ss); + break; + } + } + else { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } + throw exception::eval_error("Internal error: catch block size unrecognized"); + } + } + } + catch (Boxed_Value &except) { + for (size_t i = 1; i < this->children.size(); ++i) { + AST_NodePtr catch_block = this->children[i]; - struct Finally_AST_Node : public AST_Node { - public: - Finally_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Finally, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Finally_AST_Node() {} - }; + if (catch_block->children.size() == 1) { + //No variable capture, no guards + retval = catch_block->children[0]->eval(t_ss); + break; + } + else if (catch_block->children.size() == 2) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); + retval = catch_block->children[1]->eval(t_ss); + break; + } + else if (catch_block->children.size() == 3) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); - struct Method_AST_Node : public AST_Node { - public: - Method_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Method, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Method_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ + bool guard; + try { + guard = boxed_cast(catch_block->children[1]->eval(t_ss)); + } + catch (const exception::bad_boxed_cast &) { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } - std::vector t_param_names; - AST_NodePtr guardnode; - - //The first param of a method is always the implied this ptr. - t_param_names.push_back("this"); - - if ((this->children.size() > 3) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[2]->children.size(); ++i) { - t_param_names.push_back(this->children[2]->children[i]->text); + throw exception::eval_error("Guard condition not boolean"); + } + if (guard) { + retval = catch_block->children[2]->eval(t_ss); + break; + } + } + else { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } + throw exception::eval_error("Internal error: catch block size unrecognized"); + } + } + } + catch (...) { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } + throw; } - if (this->children.size() > 4) { - guardnode = this->children[3]; + if (this->children.back()->identifier == AST_Node_Type::Finally) { + retval = this->children.back()->children[0]->eval(t_ss); } - } - else { - //no parameters - if (this->children.size() > 3) { - guardnode = this->children[2]; - } + return retval; } - size_t numparams = t_param_names.size(); + }; - boost::shared_ptr guard; - if (guardnode) { - guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(t_ss), guardnode, - t_param_names, _1), static_cast(numparams), guardnode)); - } + struct Catch_AST_Node : public AST_Node { + public: + Catch_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Catch, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Catch_AST_Node() {} + }; - try { - const std::string & l_annotation = this->annotation?this->annotation->text:""; - const std::string & class_name = this->children[0]->text; - const std::string & function_name = this->children[1]->text; - if (function_name == class_name) { - t_ss.add(Proxy_Function - (new detail::Dynamic_Object_Constructor(class_name, Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), this->children.back(), - l_annotation, guard)))), function_name); + struct Finally_AST_Node : public AST_Node { + public: + Finally_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Finally, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Finally_AST_Node() {} + }; + struct Method_AST_Node : public AST_Node { + public: + Method_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Method, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Method_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + + std::vector t_param_names; + AST_NodePtr guardnode; + + //The first param of a method is always the implied this ptr. + t_param_names.push_back("this"); + + if ((this->children.size() > 3) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { + for (size_t i = 0; i < this->children[2]->children.size(); ++i) { + t_param_names.push_back(this->children[2]->children[i]->text); + } + + if (this->children.size() > 4) { + guardnode = this->children[3]; + } } else { - boost::optional ti; - try { - ti = t_ss.get_type(class_name); - } catch (const std::range_error &) { - // No biggie, the type name is just not known - } - t_ss.add(Proxy_Function - (new detail::Dynamic_Object_Function(class_name, Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), this->children.back(), - l_annotation, guard)), ti)), function_name); + //no parameters + if (this->children.size() > 3) { + guardnode = this->children[2]; + } } - } - catch (reserved_word_error &e) { - throw Eval_Error("Reserved word used as method name '" + e.word + "'"); - } - return Boxed_Value(); - } - }; + size_t numparams = t_param_names.size(); - struct Attr_Decl_AST_Node : public AST_Node { - public: - Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Attr_Decl, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Attr_Decl_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - try { - t_ss.add(fun(boost::function(boost::bind(&detail::Dynamic_Object_Attribute::func, this->children[0]->text, - this->children[1]->text, _1))), this->children[1]->text); + boost::shared_ptr guard; + if (guardnode) { + guard = boost::shared_ptr + (new dispatch::Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(t_ss), guardnode, + t_param_names, _1), static_cast(numparams), guardnode)); + } - } - catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as attribute '" + this->children[1]->text + "'"); - } - return Boxed_Value(); - } + try { + const std::string & l_annotation = this->annotation?this->annotation->text:""; + const std::string & class_name = this->children[0]->text; + const std::string & function_name = this->children[1]->text; + if (function_name == class_name) { + t_ss.add(Proxy_Function + (new dispatch::detail::Dynamic_Object_Constructor(class_name, Proxy_Function + (new dispatch::Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(t_ss), this->children.back(), + t_param_names, _1), static_cast(numparams), this->children.back(), + l_annotation, guard)))), function_name); - }; - - struct Shift_AST_Node : public Binary_Operator_AST_Node { - public: - Shift_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Shift, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Shift_AST_Node() {} - }; - - struct Equality_AST_Node : public Binary_Operator_AST_Node { - public: - Equality_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equality, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Equality_AST_Node() {} - }; - - struct Bitwise_And_AST_Node : public Binary_Operator_AST_Node { - public: - Bitwise_And_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_And, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Bitwise_And_AST_Node() {} - }; - - struct Bitwise_Xor_AST_Node : public Binary_Operator_AST_Node { - public: - Bitwise_Xor_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Bitwise_Xor_AST_Node() {} - }; - - struct Bitwise_Or_AST_Node : public Binary_Operator_AST_Node { - public: - Bitwise_Or_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Or, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Bitwise_Or_AST_Node() {} - }; - - struct Logical_And_AST_Node : public AST_Node { - public: - Logical_And_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_And, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Logical_And_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } - - if (this->children.size() > 1) { - for (size_t i = 1; i < this->children.size(); i += 2) { - bool lhs; - try { - lhs = boxed_cast(retval); - } - catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); - } - if (lhs) { - try { - retval = this->children[i+1]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } } else { - retval = Boxed_Value(false); + boost::optional ti; + try { + ti = t_ss.get_type(class_name); + } catch (const std::range_error &) { + // No biggie, the type name is just not known + } + t_ss.add(Proxy_Function + (new dispatch::detail::Dynamic_Object_Function(class_name, Proxy_Function + (new dispatch::Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(t_ss), this->children.back(), + t_param_names, _1), static_cast(numparams), this->children.back(), + l_annotation, guard)), ti)), function_name); + } } - } - return retval; - } - }; - - struct Logical_Or_AST_Node : public AST_Node { - public: - Logical_Or_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_Or, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Logical_Or_AST_Node() {} - virtual Boxed_Value eval(Dispatch_Engine &t_ss){ - Boxed_Value retval; - - try { - retval = this->children[0]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; + catch (const exception::reserved_word_error &e) { + throw exception::eval_error("Reserved word used as method name '" + e.word() + "'"); + } + return Boxed_Value(); } - if (this->children.size() > 1) { - for (size_t i = 1; i < this->children.size(); i += 2) { - bool lhs; - try { - lhs = boxed_cast(retval); - } - catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); - } - if (lhs) { - retval = Boxed_Value(true); - } - else { + }; + + struct Attr_Decl_AST_Node : public AST_Node { + public: + Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Attr_Decl, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Attr_Decl_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + try { + t_ss.add(fun(boost::function(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, this->children[0]->text, + this->children[1]->text, _1))), this->children[1]->text); + + } + catch (const exception::reserved_word_error &) { + throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'"); + } + return Boxed_Value(); + } + + }; + + struct Shift_AST_Node : public Binary_Operator_AST_Node { + public: + Shift_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Shift, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Shift_AST_Node() {} + }; + + struct Equality_AST_Node : public Binary_Operator_AST_Node { + public: + Equality_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equality, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Equality_AST_Node() {} + }; + + struct Bitwise_And_AST_Node : public Binary_Operator_AST_Node { + public: + Bitwise_And_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_And, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Bitwise_And_AST_Node() {} + }; + + struct Bitwise_Xor_AST_Node : public Binary_Operator_AST_Node { + public: + Bitwise_Xor_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Bitwise_Xor_AST_Node() {} + }; + + struct Bitwise_Or_AST_Node : public Binary_Operator_AST_Node { + public: + Bitwise_Or_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Or, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Bitwise_Or_AST_Node() {} + }; + + struct Logical_And_AST_Node : public AST_Node { + public: + Logical_And_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_And, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Logical_And_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval = this->children[0]->eval(t_ss); + + if (this->children.size() > 1) { + for (size_t i = 1; i < this->children.size(); i += 2) { + bool lhs; try { + lhs = boxed_cast(retval); + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("Condition not boolean"); + } + if (lhs) { retval = this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; + else { + retval = Boxed_Value(false); } } } + return retval; } - return retval; - } + }; - }; + struct Logical_Or_AST_Node : public AST_Node { + public: + Logical_Or_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_Or, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Logical_Or_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval; + + retval = this->children[0]->eval(t_ss); + + if (this->children.size() > 1) { + for (size_t i = 1; i < this->children.size(); i += 2) { + bool lhs = boxed_cast(retval); + + if (lhs) { + retval = Boxed_Value(true); + } + else { + retval = this->children[i+1]->eval(t_ss); + } + } + } + return retval; + } + + }; + } } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 2fcc3016..985cf221 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -16,563 +16,275 @@ namespace chaiscript { - enum Alphabet - { symbol_alphabet = 0 - , keyword_alphabet - , int_alphabet - , float_alphabet - , x_alphabet - , hex_alphabet - , b_alphabet - , bin_alphabet - , id_alphabet - , white_alphabet - , max_alphabet - , lengthof_alphabet = 256 - }; - - class ChaiScript_Parser { - - std::string::const_iterator m_input_pos, m_input_end; - int m_line, m_col; - std::string m_multiline_comment_begin; - std::string m_multiline_comment_end; - std::string m_singleline_comment; - boost::shared_ptr m_filename; - std::vector m_match_stack; - bool m_alphabet[max_alphabet][lengthof_alphabet]; - - std::vector > m_operator_matches; - std::vector m_operators; - - public: - ChaiScript_Parser() - : m_multiline_comment_begin("/*"), - m_multiline_comment_end("*/"), - m_singleline_comment("//") + namespace parser + { + namespace detail { - setup_operators(); + enum Alphabet + { symbol_alphabet = 0 + , keyword_alphabet + , int_alphabet + , float_alphabet + , x_alphabet + , hex_alphabet + , b_alphabet + , bin_alphabet + , id_alphabet + , white_alphabet + , max_alphabet + , lengthof_alphabet = 256 + }; } - ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor - ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator + class ChaiScript_Parser { - void setup_operators() - { - m_operators.push_back(AST_Node_Type::Logical_Or); - std::vector logical_or; - logical_or.push_back("||"); - m_operator_matches.push_back(logical_or); + std::string::const_iterator m_input_pos, m_input_end; + int m_line, m_col; + std::string m_multiline_comment_begin; + std::string m_multiline_comment_end; + std::string m_singleline_comment; + boost::shared_ptr m_filename; + std::vector m_match_stack; + bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; - m_operators.push_back(AST_Node_Type::Logical_And); - std::vector logical_and; - logical_and.push_back("&&"); - m_operator_matches.push_back(logical_and); + std::vector > m_operator_matches; + std::vector m_operators; - m_operators.push_back(AST_Node_Type::Bitwise_Or); - std::vector bitwise_or; - bitwise_or.push_back("|"); - m_operator_matches.push_back(bitwise_or); - - m_operators.push_back(AST_Node_Type::Bitwise_Xor); - std::vector bitwise_xor; - bitwise_xor.push_back("^"); - m_operator_matches.push_back(bitwise_xor); - - m_operators.push_back(AST_Node_Type::Bitwise_And); - std::vector bitwise_and; - bitwise_and.push_back("&"); - m_operator_matches.push_back(bitwise_and); - - m_operators.push_back(AST_Node_Type::Equality); - std::vector equality; - equality.push_back("=="); - equality.push_back("!="); - m_operator_matches.push_back(equality); - - m_operators.push_back(AST_Node_Type::Comparison); - std::vector comparison; - comparison.push_back("<"); - comparison.push_back("<="); - comparison.push_back(">"); - comparison.push_back(">="); - m_operator_matches.push_back(comparison); - - m_operators.push_back(AST_Node_Type::Shift); - std::vector shift; - shift.push_back("<<"); - shift.push_back(">>"); - m_operator_matches.push_back(shift); - - m_operators.push_back(AST_Node_Type::Additive); - std::vector additive; - additive.push_back("+"); - additive.push_back("-"); - m_operator_matches.push_back(additive); - - m_operators.push_back(AST_Node_Type::Multiplicative); - std::vector multiplicative; - multiplicative.push_back("*"); - multiplicative.push_back("/"); - multiplicative.push_back("%"); - m_operator_matches.push_back(multiplicative); - - m_operators.push_back(AST_Node_Type::Dot_Access); - std::vector dot_access; - dot_access.push_back("."); - m_operator_matches.push_back(dot_access); - - for ( int c = 0 ; c < lengthof_alphabet ; ++c ) { - for ( int a = 0 ; a < max_alphabet ; a ++ ) { - m_alphabet[a][c]=false; - } - } - m_alphabet[symbol_alphabet]['+']=true; - m_alphabet[symbol_alphabet]['-']=true; - m_alphabet[symbol_alphabet]['*']=true; - m_alphabet[symbol_alphabet]['/']=true; - m_alphabet[symbol_alphabet]['|']=true; - m_alphabet[symbol_alphabet]['&']=true; - m_alphabet[symbol_alphabet]['^']=true; - m_alphabet[symbol_alphabet]['=']=true; - m_alphabet[symbol_alphabet]['.']=true; - m_alphabet[symbol_alphabet]['<']=true; - m_alphabet[symbol_alphabet]['>']=true; - - for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[keyword_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[keyword_alphabet][c]=true; } - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[keyword_alphabet][c]=true; } - m_alphabet[keyword_alphabet]['_']=true; - - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[int_alphabet][c]=true; } - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[float_alphabet][c]=true; } - m_alphabet[float_alphabet]['.']=true; - - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[hex_alphabet][c]=true; } - for ( int c = 'a' ; c <= 'f' ; ++c ) { m_alphabet[hex_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'F' ; ++c ) { m_alphabet[hex_alphabet][c]=true; } - - m_alphabet[x_alphabet]['x']=true; - m_alphabet[x_alphabet]['X']=true; - - for ( int c = '0' ; c <= '1' ; ++c ) { m_alphabet[bin_alphabet][c]=true; } - m_alphabet[b_alphabet]['b']=true; - m_alphabet[b_alphabet]['B']=true; - - for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[id_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[id_alphabet][c]=true; } - m_alphabet[id_alphabet]['_'] = true; - - m_alphabet[white_alphabet][' ']=true; - m_alphabet[white_alphabet]['\t']=true; - } - - /** - * test a char in an m_alphabet - */ - bool char_in_alphabet(unsigned char c,Alphabet a) { return m_alphabet[a][c]; } - - /** - * Prints the parsed ast_nodes as a tree - */ - /* - void debug_print(AST_NodePtr t, std::string prepend = "") { - std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; - for (unsigned int j = 0; j < t->children.size(); ++j) { - debug_print(t->children[j], prepend + " "); - } - } - */ - - /** - * Shows the current stack of matched ast_nodes - */ - void show_match_stack() { - for (unsigned int i = 0; i < m_match_stack.size(); ++i) { - //debug_print(match_stack[i]); - std::cout << m_match_stack[i]->to_string(); - } - } - - /** - * Clears the stack of matched ast_nodes - */ - void clear_match_stack() { - m_match_stack.clear(); - } - - /** - * Returns the front-most AST node - */ - AST_NodePtr ast() { - return m_match_stack.front(); - } - - /** - * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node - */ - void build_match(AST_NodePtr t_t, size_t t_match_start) { - int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; - int is_deep = false; - - //so we want to take everything to the right of this and make them children - if (t_match_start != m_match_stack.size()) { - pos_line_start = m_match_stack[t_match_start]->start.line; - pos_col_start = m_match_stack[t_match_start]->start.column; - pos_line_stop = m_line; - pos_col_stop = m_col; - is_deep = true; - } - else { - pos_line_start = m_line; - pos_col_start = m_col; - pos_line_stop = m_line; - pos_col_stop = m_col; + public: + ChaiScript_Parser() + : m_multiline_comment_begin("/*"), + m_multiline_comment_end("*/"), + m_singleline_comment("//") + { + setup_operators(); } - t_t->filename = m_filename; - t_t->start.line = pos_line_start; - t_t->start.column = pos_col_start; - t_t->end.line = pos_line_stop; - t_t->end.column = pos_col_stop; + ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor + ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator - if (is_deep) { - t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.push_back(t_t); - } - else { - //todo: fix the fact that a successful match that captured no ast_nodes doesn't have any real start position - m_match_stack.push_back(t_t); - } - } + void setup_operators() + { + m_operators.push_back(AST_Node_Type::Logical_Or); + std::vector logical_or; + logical_or.push_back("||"); + m_operator_matches.push_back(logical_or); - /** - * Check to see if there is more text parse - */ - inline bool has_more_input() { - return (m_input_pos != m_input_end); - } + m_operators.push_back(AST_Node_Type::Logical_And); + std::vector logical_and; + logical_and.push_back("&&"); + m_operator_matches.push_back(logical_and); - /** - * Skips any multi-line or single-line comment - */ - bool SkipComment() { - bool retval = false; + m_operators.push_back(AST_Node_Type::Bitwise_Or); + std::vector bitwise_or; + bitwise_or.push_back("|"); + m_operator_matches.push_back(bitwise_or); - if (Symbol_(m_multiline_comment_begin.c_str())) { - while (m_input_pos != m_input_end) { - if (Symbol_(m_multiline_comment_end.c_str())) { - break; - } - else if (!Eol_()) { - ++m_col; - ++m_input_pos; + m_operators.push_back(AST_Node_Type::Bitwise_Xor); + std::vector bitwise_xor; + bitwise_xor.push_back("^"); + m_operator_matches.push_back(bitwise_xor); + + m_operators.push_back(AST_Node_Type::Bitwise_And); + std::vector bitwise_and; + bitwise_and.push_back("&"); + m_operator_matches.push_back(bitwise_and); + + m_operators.push_back(AST_Node_Type::Equality); + std::vector equality; + equality.push_back("=="); + equality.push_back("!="); + m_operator_matches.push_back(equality); + + m_operators.push_back(AST_Node_Type::Comparison); + std::vector comparison; + comparison.push_back("<"); + comparison.push_back("<="); + comparison.push_back(">"); + comparison.push_back(">="); + m_operator_matches.push_back(comparison); + + m_operators.push_back(AST_Node_Type::Shift); + std::vector shift; + shift.push_back("<<"); + shift.push_back(">>"); + m_operator_matches.push_back(shift); + + m_operators.push_back(AST_Node_Type::Additive); + std::vector additive; + additive.push_back("+"); + additive.push_back("-"); + m_operator_matches.push_back(additive); + + m_operators.push_back(AST_Node_Type::Multiplicative); + std::vector multiplicative; + multiplicative.push_back("*"); + multiplicative.push_back("/"); + multiplicative.push_back("%"); + m_operator_matches.push_back(multiplicative); + + m_operators.push_back(AST_Node_Type::Dot_Access); + std::vector dot_access; + dot_access.push_back("."); + m_operator_matches.push_back(dot_access); + + for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { + for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) { + m_alphabet[a][c]=false; } } - retval = true; - } - else if (Symbol_(m_singleline_comment.c_str())) { - while (m_input_pos != m_input_end) { - if (Symbol_("\r\n")) { - m_input_pos -= 2; - break; - } - else if (Char_('\n')) { - --m_input_pos; - break; - } - else { - ++m_col; - ++m_input_pos; - } - } - retval = true; - } - return retval; - } + m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('*')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('/')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('|')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('&')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('^')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('=')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('.')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('<')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('>')]=true; - /** - * Skips ChaiScript whitespace, which means space and tab, but not cr/lf - */ - bool SkipWS() { - bool retval = false; - while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,white_alphabet) ) { - ++m_input_pos; - ++m_col; - retval = true; + for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + m_alphabet[detail::keyword_alphabet][static_cast('_')]=true; + + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::int_alphabet][c]=true; } + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::float_alphabet][c]=true; } + m_alphabet[detail::float_alphabet][static_cast('.')]=true; + + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + for ( int c = 'a' ; c <= 'f' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'F' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + + m_alphabet[detail::x_alphabet][static_cast('x')]=true; + m_alphabet[detail::x_alphabet][static_cast('X')]=true; + + for ( int c = '0' ; c <= '1' ; ++c ) { m_alphabet[detail::bin_alphabet][c]=true; } + m_alphabet[detail::b_alphabet][static_cast('b')]=true; + m_alphabet[detail::b_alphabet][static_cast('B')]=true; + + for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } + m_alphabet[detail::id_alphabet][static_cast('_')] = true; + + m_alphabet[detail::white_alphabet][static_cast(' ')]=true; + m_alphabet[detail::white_alphabet][static_cast('\t')]=true; + } + + /** + * test a char in an m_alphabet + */ + bool char_in_alphabet(unsigned char c, detail::Alphabet a) { return m_alphabet[a][c]; } + + /** + * Prints the parsed ast_nodes as a tree + */ + /* + void debug_print(AST_NodePtr t, std::string prepend = "") { + std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; + for (unsigned int j = 0; j < t->children.size(); ++j) { + debug_print(t->children[j], prepend + " "); + } + } + */ + + /** + * Shows the current stack of matched ast_nodes + */ + void show_match_stack() { + for (unsigned int i = 0; i < m_match_stack.size(); ++i) { + //debug_print(match_stack[i]); + std::cout << m_match_stack[i]->to_string(); } - else if (SkipComment()) { - retval = true; + } + + /** + * Clears the stack of matched ast_nodes + */ + void clear_match_stack() { + m_match_stack.clear(); + } + + /** + * Returns the front-most AST node + */ + AST_NodePtr ast() { + return m_match_stack.front(); + } + + /** + * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node + */ + void build_match(AST_NodePtr t_t, size_t t_match_start) { + int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; + int is_deep = false; + + //so we want to take everything to the right of this and make them children + if (t_match_start != m_match_stack.size()) { + pos_line_start = m_match_stack[t_match_start]->start.line; + pos_col_start = m_match_stack[t_match_start]->start.column; + pos_line_stop = m_line; + pos_col_stop = m_col; + is_deep = true; } else { - break; + pos_line_start = m_line; + pos_col_start = m_col; + pos_line_stop = m_line; + pos_col_stop = m_col; } - } - return retval; - } - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Float_() { - bool retval = false; - std::string::const_iterator start = m_input_pos; + t_t->filename = m_filename; + t_t->start.line = pos_line_start; + t_t->start.column = pos_col_start; + t_t->end.line = pos_line_stop; + t_t->end.column = pos_col_stop; - if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { - while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { - ++m_input_pos; - ++m_col; - } - if (has_more_input() && (*m_input_pos == '.')) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } - } - } - return retval; - } - - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Hex_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; - ++m_col; - - if (has_more_input() && char_in_alphabet(*m_input_pos,x_alphabet) ) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } + if (is_deep) { + t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); + m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); + m_match_stack.push_back(t_t); } else { - --m_input_pos; - --m_col; + //todo: fix the fact that a successful match that captured no ast_nodes doesn't have any real start position + m_match_stack.push_back(t_t); } } - return retval; - } - - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Binary_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; - ++m_col; - - if (has_more_input() && char_in_alphabet(*m_input_pos,b_alphabet) ) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } - } - else { - --m_input_pos; - --m_col; - } + /** + * Check to see if there is more text parse + */ + inline bool has_more_input() { + return (m_input_pos != m_input_end); } - return retval; - } + /** + * Skips any multi-line or single-line comment + */ + bool SkipComment() { + bool retval = false; - /** - * Reads a number from the input, detecting if it's an integer or floating point - */ - bool Num(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Hex_() || Float_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { - if (Hex_()) { - std::string match(start, m_input_pos); - std::stringstream ss(match); - unsigned int temp_int; - ss >> std::hex >> temp_int; - - std::ostringstream out_int; - out_int << static_cast(temp_int); - AST_NodePtr t(new Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - if (Binary_()) { - std::string match(start, m_input_pos); - int temp_int = 0; - size_t pos = 0, end = match.length(); - - while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { - temp_int <<= 1; - if (match[pos] == '1') { - temp_int += 1; - } - ++pos; - } - - std::ostringstream out_int; - out_int << temp_int; - AST_NodePtr t(new Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - if (Float_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - std::string match(start, m_input_pos); - if ((match.size() > 0) && (match[0] == '0')) { - std::stringstream ss(match); - unsigned int temp_int; - ss >> std::oct >> temp_int; - - std::ostringstream out_int; - out_int << int(temp_int); - AST_NodePtr t(new Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - else { - AST_NodePtr t(new Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - return true; - } - } - else { - return false; - } - } - } - - /** - * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace - */ - bool Id_() { - bool retval = false; - if (has_more_input() && char_in_alphabet(*m_input_pos,id_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,keyword_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else if (has_more_input() && (*m_input_pos == '`')) { - retval = true; - ++m_col; - ++m_input_pos; - std::string::const_iterator start = m_input_pos; - - while (has_more_input() && (*m_input_pos != '`')) { - if (Eol()) { - throw Eval_Error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); - } - else { - ++m_input_pos; - ++m_col; - } - } - - if (start == m_input_pos) { - throw Eval_Error("Missing contents of identifier literal", File_Position(m_line, m_col), *m_filename); - } - else if (m_input_pos == m_input_end) { - throw Eval_Error("Incomplete identifier literal", File_Position(m_line, m_col), *m_filename); - } - - ++m_col; - ++m_input_pos; - } - return retval; - } - - /** - * Reads (and potentially captures) an identifier from input - */ - bool Id(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Id_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Id_()) { - if (*start == '`') { - //Id Literal - std::string match(start+1, m_input_pos-1); - AST_NodePtr t(new Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - std::string match(start, m_input_pos); - AST_NodePtr t(new Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - } - else { - return false; - } - } - } - - /** - * Checks for a node annotation of the form "#" - */ - bool Annotation() { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Symbol_("#")) { - do { + if (Symbol_(m_multiline_comment_begin.c_str())) { while (m_input_pos != m_input_end) { - if (Eol_()) { + if (Symbol_(m_multiline_comment_end.c_str())) { + break; + } + else if (!Eol_()) { + ++m_col; + ++m_input_pos; + } + } + retval = true; + } + else if (Symbol_(m_singleline_comment.c_str())) { + while (m_input_pos != m_input_end) { + if (Symbol_("\r\n")) { + m_input_pos -= 2; + break; + } + else if (Char_('\n')) { + --m_input_pos; break; } else { @@ -580,325 +292,303 @@ namespace chaiscript ++m_input_pos; } } - } while (Symbol("#")); - - std::string match(start, m_input_pos); - AST_NodePtr t(new Annotation_AST_Node(match, AST_Node_Type::Annotation, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; + retval = true; + } + return retval; } - else { - return false; - } - } - /** - * Reads a quoted string from input, without skipping initial whitespace - */ - bool Quoted_String_() { - bool retval = false; - char prev_char = 0; - if (has_more_input() && (*m_input_pos == '\"')) { - retval = true; - prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; - - while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; - } - else { - prev_char = *m_input_pos; - } + /** + * Skips ChaiScript whitespace, which means space and tab, but not cr/lf + */ + bool SkipWS() { + bool retval = false; + while (has_more_input()) { + if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) ) { ++m_input_pos; ++m_col; + retval = true; } - } - - if (has_more_input()) { - ++m_input_pos; - ++m_col; - } - else { - throw Eval_Error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } - - /** - * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. - */ - bool Quoted_String(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Quoted_String_()) { - std::string match; - bool is_escaped = false; - bool is_interpolated = false; - bool saw_interpolation_marker = false; - size_t prev_stack_top = m_match_stack.size(); - - //for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - std::string::const_iterator s = start + 1, end = m_input_pos - 1; - - while (s != end) { - if (saw_interpolation_marker) { - if (*s == '{') { - //We've found an interpolation point - - if (is_interpolated) { - //If we've seen previous interpolation, add on instead of making a new one - AST_NodePtr plus(new Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - - AST_NodePtr t(new Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); - } - else { - AST_NodePtr t(new Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - //We've finished with the part of the string up to this point, so clear it - match = ""; - - AST_NodePtr plus(new Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - - std::string eval_match; - - ++s; - while ((*s != '}') && (s != end)) { - eval_match.push_back(*s); - ++s; - } - if (*s == '}') { - is_interpolated = true; - ++s; - - size_t tostr_stack_top = m_match_stack.size(); - - AST_NodePtr tostr(new Id_AST_Node("to_string", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(tostr); - - size_t ev_stack_top = m_match_stack.size(); - - AST_NodePtr ev(new Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(ev); - - size_t arg_stack_top = m_match_stack.size(); - - AST_NodePtr t(new Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - - build_match(AST_NodePtr(new Arg_List_AST_Node()), arg_stack_top); - - build_match(AST_NodePtr(new Inplace_Fun_Call_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new Arg_List_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new Fun_Call_AST_Node()), tostr_stack_top); - - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); - } - else { - throw Eval_Error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back('$'); - } - saw_interpolation_marker = false; - } - else { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - case ('$') : match.push_back('$'); break; - default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); - } - } - else if (*s == '$') { - saw_interpolation_marker = true; - } - else { - match.push_back(*s); - } - is_escaped = false; - } - ++s; - } - } - if (is_interpolated) { - AST_NodePtr plus(new Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - - AST_NodePtr t(new Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); + else if (SkipComment()) { + retval = true; } else { - AST_NodePtr t(new Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + break; } - return true; - } - else { - return false; } + return retval; } - } - /** - * Reads a character group from input, without skipping initial whitespace - */ - bool Single_Quoted_String_() { - bool retval = false; - char prev_char = 0; - if (has_more_input() && (*m_input_pos == '\'')) { - retval = true; - prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Float_() { + bool retval = false; + std::string::const_iterator start = m_input_pos; - while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; + if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { + ++m_input_pos; + ++m_col; + } + if (has_more_input() && (*m_input_pos == '.')) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { + ++m_input_pos; + ++m_col; + } } else { - prev_char = *m_input_pos; + --m_input_pos; + --m_col; } + } + } + return retval; + } + + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Hex_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '0')) { + ++m_input_pos; + ++m_col; + + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { + ++m_input_pos; + ++m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + + return retval; + } + + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Binary_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '0')) { + ++m_input_pos; + ++m_col; + + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { + ++m_input_pos; + ++m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + + return retval; + } + + /** + * Reads a number from the input, detecting if it's an integer or floating point + */ + bool Num(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Hex_() || Float_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { + if (Hex_()) { + std::string match(start, m_input_pos); + std::stringstream ss(match); + unsigned int temp_int; + ss >> std::hex >> temp_int; + + std::ostringstream out_int; + out_int << static_cast(temp_int); + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + if (Binary_()) { + std::string match(start, m_input_pos); + int temp_int = 0; + size_t pos = 0, end = match.length(); + + while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { + temp_int <<= 1; + if (match[pos] == '1') { + temp_int += 1; + } + ++pos; + } + + std::ostringstream out_int; + out_int << temp_int; + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + if (Float_()) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + std::string match(start, m_input_pos); + if ((match.size() > 0) && (match[0] == '0')) { + std::stringstream ss(match); + unsigned int temp_int; + ss >> std::oct >> temp_int; + + std::ostringstream out_int; + out_int << int(temp_int); + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + else { + AST_NodePtr t(new eval::Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + return true; + } + } + else { + return false; + } + } + } + + /** + * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace + */ + bool Id_() { + bool retval = false; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { ++m_input_pos; ++m_col; } } - - if (m_input_pos != m_input_end) { - ++m_input_pos; + else if (has_more_input() && (*m_input_pos == '`')) { + retval = true; ++m_col; - } - else { - throw Eval_Error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } + ++m_input_pos; + std::string::const_iterator start = m_input_pos; - /** - * Reads (and potentially captures) a char group from input. Translates escaped sequences. - */ - bool Single_Quoted_String(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Single_Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Single_Quoted_String_()) { - std::string match; - bool is_escaped = false; - for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } + while (has_more_input() && (*m_input_pos != '`')) { + if (Eol()) { + throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); } else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back(*s); - } - is_escaped = false; + ++m_input_pos; + ++m_col; } } - AST_NodePtr t(new Single_Quoted_String_AST_Node(match, AST_Node_Type::Single_Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; + + if (start == m_input_pos) { + throw exception::eval_error("Missing contents of identifier literal", File_Position(m_line, m_col), *m_filename); + } + else if (m_input_pos == m_input_end) { + throw exception::eval_error("Incomplete identifier literal", File_Position(m_line, m_col), *m_filename); + } + + ++m_col; + ++m_input_pos; + } + return retval; + } + + /** + * Reads (and potentially captures) an identifier from input + */ + bool Id(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Id_(); } else { - return false; + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Id_()) { + if (*start == '`') { + //Id Literal + std::string match(start+1, m_input_pos-1); + AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + } + else { + return false; + } } } - } - /** - * Reads a char from input if it matches the parameter, without skipping initial whitespace - */ - bool Char_(char c) { - bool retval = false; - if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; - ++m_col; - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) a char from input if it matches the parameter - */ - bool Char(char t_c, bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Char_(t_c); - } - else { + /** + * Checks for a node annotation of the form "#" + */ + bool Annotation() { + SkipWS(); std::string::const_iterator start = m_input_pos; int prev_col = m_col; int prev_line = m_line; - if (Char_(t_c)) { + if (Symbol_("#")) { + do { + while (m_input_pos != m_input_end) { + if (Eol_()) { + break; + } + else { + ++m_col; + ++m_input_pos; + } + } + } while (Symbol("#")); + std::string match(start, m_input_pos); - AST_NodePtr t(new Char_AST_Node(match, AST_Node_Type::Char, m_filename, prev_line, prev_col, m_line, m_col)); + AST_NodePtr t(new eval::Annotation_AST_Node(match, AST_Node_Type::Annotation, m_filename, prev_line, prev_col, m_line, m_col)); m_match_stack.push_back(t); return true; } @@ -906,1066 +596,1387 @@ namespace chaiscript return false; } } - } - /** - * Reads a string from input if it matches the parameter, without skipping initial whitespace - */ - bool Keyword_(const char *t_s) { - bool retval = false; - int len = static_cast(strlen(t_s)); + /** + * Reads a quoted string from input, without skipping initial whitespace + */ + bool Quoted_String_() { + bool retval = false; + char prev_char = 0; + if (has_more_input() && (*m_input_pos == '\"')) { + retval = true; + prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; - if ((m_input_end - m_input_pos) >= len) { - std::string::const_iterator tmp = m_input_pos; - for (int i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; + while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; + } + } + + if (has_more_input()) { + ++m_input_pos; + ++m_col; + } + else { + throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); } - ++tmp; } - retval = true; - m_input_pos = tmp; - m_col += len; + return retval; } - return retval; - } + /** + * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. + */ + bool Quoted_String(bool t_capture = false) { + SkipWS(); - /** - * Reads (and potentially captures) a string from input if it matches the parameter - */ - bool Keyword(const char *t_s, bool t_capture = false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Keyword_(t_s); - // ignore substring matches - if ( retval && has_more_input() && char_in_alphabet(*m_input_pos,keyword_alphabet) ) { + if (!t_capture) { + return Quoted_String_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Quoted_String_()) { + std::string match; + bool is_escaped = false; + bool is_interpolated = false; + bool saw_interpolation_marker = false; + size_t prev_stack_top = m_match_stack.size(); + + //for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { + std::string::const_iterator s = start + 1, end = m_input_pos - 1; + + while (s != end) { + if (saw_interpolation_marker) { + if (*s == '{') { + //We've found an interpolation point + + if (is_interpolated) { + //If we've seen previous interpolation, add on instead of making a new one + AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(plus); + + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + + //We've finished with the part of the string up to this point, so clear it + match = ""; + + AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(plus); + + std::string eval_match; + + ++s; + while ((*s != '}') && (s != end)) { + eval_match.push_back(*s); + ++s; + } + if (*s == '}') { + is_interpolated = true; + ++s; + + size_t tostr_stack_top = m_match_stack.size(); + + AST_NodePtr tostr(new eval::Id_AST_Node("to_string", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(tostr); + + size_t ev_stack_top = m_match_stack.size(); + + AST_NodePtr ev(new eval::Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(ev); + + size_t arg_stack_top = m_match_stack.size(); + + AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top); + + build_match(AST_NodePtr(new eval::Inplace_Fun_Call_AST_Node()), ev_stack_top); + + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), ev_stack_top); + + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); + + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); + } + } + else { + match.push_back('$'); + } + saw_interpolation_marker = false; + } + else { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } + else { + is_escaped = true; + } + } + else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + case ('$') : match.push_back('$'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } + else if (*s == '$') { + saw_interpolation_marker = true; + } + else { + match.push_back(*s); + } + is_escaped = false; + } + ++s; + } + } + if (is_interpolated) { + AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(plus); + + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + return true; + } + else { + return false; + } + } + } + + /** + * Reads a character group from input, without skipping initial whitespace + */ + bool Single_Quoted_String_() { + bool retval = false; + char prev_char = 0; + if (has_more_input() && (*m_input_pos == '\'')) { + retval = true; + prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; + + while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; + } + } + + if (m_input_pos != m_input_end) { + ++m_input_pos; + ++m_col; + } + else { + throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); + } + } + return retval; + } + + /** + * Reads (and potentially captures) a char group from input. Translates escaped sequences. + */ + bool Single_Quoted_String(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Single_Quoted_String_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Single_Quoted_String_()) { + std::string match; + bool is_escaped = false; + for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } + else { + is_escaped = true; + } + } + else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } + else { + match.push_back(*s); + } + is_escaped = false; + } + } + AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, AST_Node_Type::Single_Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a char from input if it matches the parameter, without skipping initial whitespace + */ + bool Char_(char c) { + bool retval = false; + if (has_more_input() && (*m_input_pos == c)) { + ++m_input_pos; + ++m_col; + retval = true; + } + + return retval; + } + + /** + * Reads (and potentially captures) a char from input if it matches the parameter + */ + bool Char(char t_c, bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Char_(t_c); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Char_(t_c)) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Char_AST_Node(match, AST_Node_Type::Char, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a string from input if it matches the parameter, without skipping initial whitespace + */ + bool Keyword_(const char *t_s) { + bool retval = false; + int len = static_cast(strlen(t_s)); + + if ((m_input_end - m_input_pos) >= len) { + std::string::const_iterator tmp = m_input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; + } + ++tmp; + } + retval = true; + m_input_pos = tmp; + m_col += len; + } + + return retval; + } + + /** + * Reads (and potentially captures) a string from input if it matches the parameter + */ + bool Keyword(const char *t_s, bool t_capture = false) { + SkipWS(); + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + bool retval = Keyword_(t_s); + // ignore substring matches + if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { m_input_pos = start; m_col = prev_col; m_line = prev_line; retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - return retval; - } - - /** - * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - */ - bool Symbol_(const char *t_s) { - bool retval = false; - int len = static_cast(strlen(t_s)); - - if ((m_input_end - m_input_pos) >= len) { - std::string::const_iterator tmp = m_input_pos; - for (int i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += len; - } - return retval; - } - - /** - * Reads (and potentially captures) a symbol group from input if it matches the parameter - */ - bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Symbol_(t_s); - // ignore substring matches - if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,symbol_alphabet)) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - return retval; - } - - /** - * Reads an end-of-line group from input, without skipping initial whitespace - */ - bool Eol_() { - bool retval = false; - - if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { - retval = true; - ++m_line; - m_col = 1; - } - else if (has_more_input() && Char_(';')) { - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) an end-of-line group from input - */ - bool Eol(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Eol_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Eol_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new Eol_AST_Node(match, AST_Node_Type::Eol, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a comma-separated list of values from input - */ - bool Arg_List() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Equation()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Equation()) { - throw Eval_Error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads possible special container values, including ranges and map_pairs - */ - bool Container_Arg_List() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Value_Range()) { - retval = true; - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); - } - else if (Map_Pair()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Map_Pair()) { - throw Eval_Error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); - } - else if (Operator()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Operator()) { - throw Eval_Error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); - } - - return retval; - - } - - /** - * Reads a lambda (anonymous function) from input - */ - bool Lambda() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("fun")) { - retval = true; - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); } + return retval; } - while (Eol()) {} + /** + * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + */ + bool Symbol_(const char *t_s) { + bool retval = false; + int len = static_cast(strlen(t_s)); - if (!Block()) { - throw Eval_Error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new Lambda_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a function definition from input - */ - bool Def() { - bool retval = false; - bool is_annotated = false; - bool is_method = false; - AST_NodePtr annotation; - - if (Annotation()) { - while (Eol_()) {} - annotation = m_match_stack.back(); - m_match_stack.pop_back(); - is_annotated = true; - } - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("def")) { - retval = true; - - if (!Id(true)) { - throw Eval_Error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); - } - - if (Symbol("::", false)) { - //We're now a method - is_method = true; - - if (!Id(true)) { - throw Eval_Error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); - } - } - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - - if (Char(':')) { - if (!Operator()) { - throw Eval_Error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - if (!Block()) { - throw Eval_Error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - - if (is_method) { - build_match(AST_NodePtr(new Method_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new Def_AST_Node()), prev_stack_top); - } - - if (is_annotated) { - m_match_stack.back()->annotation = annotation; - } - } - - return retval; - } - - /** - * Reads a function definition from input - */ - bool Try() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("try")) { - retval = true; - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("catch", false)) { - size_t catch_stack_top = m_match_stack.size(); - if (Char('(')) { - if (!(Id(true) && Char(')'))) { - throw Eval_Error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + if ((m_input_end - m_input_pos) >= len) { + std::string::const_iterator tmp = m_input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; } - if (Char(':')) { - if (!Operator()) { - throw Eval_Error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + ++tmp; + } + retval = true; + m_input_pos = tmp; + m_col += len; + } + + return retval; + } + + /** + * Reads (and potentially captures) a symbol group from input if it matches the parameter + */ + bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { + SkipWS(); + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + bool retval = Symbol_(t_s); + // ignore substring matches + if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; + } + + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + + return retval; + } + + /** + * Reads an end-of-line group from input, without skipping initial whitespace + */ + bool Eol_() { + bool retval = false; + + if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { + retval = true; + ++m_line; + m_col = 1; + } + else if (has_more_input() && Char_(';')) { + retval = true; + } + + return retval; + } + + /** + * Reads (and potentially captures) an end-of-line group from input + */ + bool Eol(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Eol_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Eol_()) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Eol_AST_Node(match, AST_Node_Type::Eol, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a comma-separated list of values from input + */ + bool Arg_List() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Equation()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Equation()) { + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + + return retval; + } + + /** + * Reads possible special container values, including ranges and map_pairs + */ + bool Container_Arg_List() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Value_Range()) { + retval = true; + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + else if (Map_Pair()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Map_Pair()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + else if (Operator()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Operator()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + + return retval; + + } + + /** + * Reads a lambda (anonymous function) from input + */ + bool Lambda() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("fun")) { + retval = true; + + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } } while (Eol()) {} if (!Block()) { - throw Eval_Error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Catch_AST_Node()), catch_stack_top); - has_matches = true; + + build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); } + + return retval; } - while (Eol()) {} - if (Keyword("finally", false)) { - size_t finally_stack_top = m_match_stack.size(); - while (Eol()) {} + /** + * Reads a function definition from input + */ + bool Def() { + bool retval = false; + bool is_annotated = false; + bool is_method = false; + AST_NodePtr annotation; - if (!Block()) { - throw Eval_Error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); + if (Annotation()) { + while (Eol_()) {} + annotation = m_match_stack.back(); + m_match_stack.pop_back(); + is_annotated = true; } - build_match(AST_NodePtr(new Finally_AST_Node()), finally_stack_top); - } - build_match(AST_NodePtr(new Try_AST_Node()), prev_stack_top); - } + size_t prev_stack_top = m_match_stack.size(); - return retval; - } + if (Keyword("def")) { + retval = true; - /** - * Reads an if/elseif/else block from input - */ - bool If() { - bool retval = false; + if (!Id(true)) { + throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); + } - size_t prev_stack_top = m_match_stack.size(); + if (Symbol("::", false)) { + //We're now a method + is_method = true; - if (Keyword("if")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("else", true)) { - if (Keyword("if")) { - m_match_stack.back()->text = "else if"; - if (!Char('(')) { - throw Eval_Error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + if (!Id(true)) { + throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); } + } - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); } + } - while (Eol()) {} + while (Eol()) {} - if (!Block()) { - throw Eval_Error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); } - has_matches = true; + } + + while (Eol()) {} + if (!Block()) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + + if (is_method) { + build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); } else { + build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); + } + + if (is_annotated) { + m_match_stack.back()->annotation = annotation; + } + } + + return retval; + } + + /** + * Reads a function definition from input + */ + bool Try() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("try")) { + retval = true; + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("catch", false)) { + size_t catch_stack_top = m_match_stack.size(); + if (Char('(')) { + if (!(Id(true) && Char(')'))) { + throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + } + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + } + } + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + } + build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); + has_matches = true; + } + } + while (Eol()) {} + if (Keyword("finally", false)) { + size_t finally_stack_top = m_match_stack.size(); + while (Eol()) {} if (!Block()) { - throw Eval_Error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); } - has_matches = true; - } - } - } - - build_match(AST_NodePtr(new If_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a while block from input - */ - bool While() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("while")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new While_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads the C-style for conditions from input - */ - bool For_Guards() { - Equation(); - - if (Char(';') && Operator() && Char(';') && Equation()) { - return true; - } - else { - throw Eval_Error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename); - } - } - - /** - * Reads a for block from input - */ - bool For() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("for")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(For_Guards() && Char(')'))) { - throw Eval_Error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new For_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a curly-brace C-style block from input - */ - bool Block() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('{')) { - retval = true; - - Statements(); - if (!Char('}')) { - throw Eval_Error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new Block_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a return statement from input - */ - bool Return() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("return")) { - retval = true; - - Operator(); - build_match(AST_NodePtr(new Return_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a break statement from input - */ - bool Break() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("break")) { - retval = true; - - build_match(AST_NodePtr(new Break_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads an identifier, then proceeds to check if it's a function or array call - */ - bool Id_Fun_Array() { - bool retval = false; - std::string::const_iterator prev_pos = m_input_pos; - - size_t prev_stack_top = m_match_stack.size(); - if (Id(true)) { - retval = true; - bool has_more = true; - - while (has_more) { - has_more = false; - - if (Char('(')) { - has_more = true; - - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); } - build_match(AST_NodePtr(new Fun_Call_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); } - else if (Char('[')) { - has_more = true; - if (!(Operator() && Char(']'))) { - throw Eval_Error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + return retval; + } + + /** + * Reads an if/elseif/else block from input + */ + bool If() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("if")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Array_Call_AST_Node()), prev_stack_top); + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("else", true)) { + if (Keyword("if")) { + AST_NodePtr back(m_match_stack.back()); + m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if", back->identifier)); + m_match_stack.back()->start = back->start; + m_match_stack.back()->end = back->end; + m_match_stack.back()->children = back->children; + m_match_stack.back()->annotation = back->annotation; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } + else { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } + } + } + + build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); } - } - } - return retval; - } - - /** - * Reads a variable declaration from input - */ - bool Var_Decl() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("var")) { - retval = true; - - if (!Id(true)) { - throw Eval_Error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + return retval; } - build_match(AST_NodePtr(new Var_Decl_AST_Node()), prev_stack_top); - } - else if (Keyword("attr")) { - retval = true; + /** + * Reads a while block from input + */ + bool While() { + bool retval = false; - if (!Id(true)) { - throw Eval_Error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Symbol("::", false)) { - throw Eval_Error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Id(true)) { - throw Eval_Error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); - } + size_t prev_stack_top = m_match_stack.size(); + if (Keyword("while")) { + retval = true; - build_match(AST_NodePtr(new Attr_Decl_AST_Node()), prev_stack_top); - } + if (!Char('(')) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } - return retval; - } + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } - /** - * Reads an expression surrounded by parentheses from input - */ - bool Paren_Expression() { - bool retval = false; + while (Eol()) {} - if (Char('(')) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete expression", File_Position(m_line, m_col), *m_filename); - } - if (!Char(')')) { - throw Eval_Error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } + if (!Block()) { + throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); + } - /** - * Reads, and identifies, a short-form container initialization from input - */ - bool Inline_Container() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('[')) { - retval = true; - Container_Arg_List(); - if (!Char(']')) { - throw Eval_Error("Missing closing square bracket", File_Position(m_line, m_col), *m_filename); - } - if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { - build_match(AST_NodePtr(new Inline_Range_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); } - else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { - build_match(AST_NodePtr(new Inline_Map_AST_Node()), prev_stack_top); + + return retval; + } + + /** + * Reads the C-style for conditions from input + */ + bool For_Guards() { + Equation(); + + if (Char(';') && Operator() && Char(';') && Equation()) { + return true; } else { - build_match(AST_NodePtr(new Inline_Array_AST_Node()), prev_stack_top); + throw exception::eval_error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename); } } - else { - build_match(AST_NodePtr(new Inline_Array_AST_Node()), prev_stack_top); - } - } - return retval; - } + /** + * Reads a for block from input + */ + bool For() { + bool retval = false; - /** - * Reads a unary prefixed expression from input - */ - bool Prefix() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); + if (Keyword("for")) { + retval = true; - if (Symbol("++", true)) { - retval = true; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + if (!(For_Guards() && Char(')'))) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } - else if (Symbol("--", true)) { - retval = true; + /** + * Reads a curly-brace C-style block from input + */ + bool Block() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } - else if (Char('-', true)) { - retval = true; + /** + * Reads a return statement from input + */ + bool Return() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("return")) { + retval = true; + + Operator(); + build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } - else if (Char('+', true)) { - retval = true; + /** + * Reads a break statement from input + */ + bool Break() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("break")) { + retval = true; + + build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } - else if (Char('!', true)) { - retval = true; + /** + * Reads an identifier, then proceeds to check if it's a function or array call + */ + bool Id_Fun_Array() { + bool retval = false; + std::string::const_iterator prev_pos = m_input_pos; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); - } + size_t prev_stack_top = m_match_stack.size(); + if (Id(true)) { + retval = true; + bool has_more = true; - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } - else if (Char('~', true)) { - retval = true; + while (has_more) { + has_more = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } + if (Char('(')) { + has_more = true; - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); - } + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + } - return retval; - } - - /** - * Parses any of a group of 'value' style ast_node groups from input - */ - bool Value() { - if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container()) { - return true; - } - else { - return false; - } - } - - bool Operator_Helper(size_t t_precedence) { - for (size_t i = 0; i < m_operator_matches[t_precedence].size(); ++i) { - if (Symbol(m_operator_matches[t_precedence][i].c_str(), true)) { - return true; - } - } - return false; - } - - bool Operator(size_t t_precedence = 0) { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (t_precedence < m_operators.size()) { - if (Operator(t_precedence+1)) { - retval = true; - if (Operator_Helper(t_precedence)) { - do { - if (!Operator(t_precedence+1)) { - throw Eval_Error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); } - } while (Operator_Helper(t_precedence)); + else if (Char('[')) { + has_more = true; - switch (m_operators[t_precedence]) { - case(AST_Node_Type::Comparison) : - build_match(AST_NodePtr(new Comparison_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Dot_Access) : - build_match(AST_NodePtr(new Dot_Access_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Additive) : - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Multiplicative) : - build_match(AST_NodePtr(new Multiplicative_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Shift) : - build_match(AST_NodePtr(new Shift_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Equality) : - build_match(AST_NodePtr(new Equality_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_And) : - build_match(AST_NodePtr(new Bitwise_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Xor) : - build_match(AST_NodePtr(new Bitwise_Xor_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Or) : - build_match(AST_NodePtr(new Bitwise_Or_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_And) : - build_match(AST_NodePtr(new Logical_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_Or) : - build_match(AST_NodePtr(new Logical_Or_AST_Node()), prev_stack_top); - break; - default: - throw Eval_Error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + if (!(Operator() && Char(']'))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); + } } } + + return retval; } - } - else { - return Value(); - } - return retval; - } + /** + * Reads a variable declaration from input + */ + bool Var_Decl() { + bool retval = false; - /** - * Reads a pair of values used to create a map initialization from input - */ - bool Map_Pair() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; + if (Keyword("var")) { + retval = true; - if (Operator()) { - if (Symbol(":")) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + if (!Id(true)) { + throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); + } + else if (Keyword("attr")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Symbol("::", false)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Id(true)) { + throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); + } + + + build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); } - build_match(AST_NodePtr(new Map_Pair_AST_Node()), prev_stack_top); + return retval; } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); + + /** + * Reads an expression surrounded by parentheses from input + */ + bool Paren_Expression() { + bool retval = false; + + if (Char('(')) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); + } + if (!Char(')')) { + throw exception::eval_error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename); + } } + return retval; } - } - return retval; - } + /** + * Reads, and identifies, a short-form container initialization from input + */ + bool Inline_Container() { + bool retval = false; - /** - * Reads a pair of values used to create a range initialization from input - */ - bool Value_Range() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; - - if (Operator()) { - if (Symbol("..")) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + if (Char('[')) { + retval = true; + Container_Arg_List(); + if (!Char(']')) { + throw exception::eval_error("Missing closing square bracket", File_Position(m_line, m_col), *m_filename); + } + if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { + build_match(AST_NodePtr(new eval::Inline_Range_AST_Node()), prev_stack_top); + } + else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { + build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); + } + else { + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); + } + } + else { + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); + } } - build_match(AST_NodePtr(new Value_Range_AST_Node()), prev_stack_top); + return retval; } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); + + /** + * Reads a unary prefixed expression from input + */ + bool Prefix() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Symbol("++", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } - } - } + else if (Symbol("--", true)) { + retval = true; - return retval; - } + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + } - /** - * Parses a string of binary equation operators - */ - bool Equation() { - bool retval = false; + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('-', true)) { + retval = true; - size_t prev_stack_top = m_match_stack.size(); + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + } - if (Operator()) { - retval = true; - if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || - Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || - Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || - Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { - if (!Equation()) { - throw Eval_Error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('+', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('!', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('~', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } - build_match(AST_NodePtr(new Equation_AST_Node()), prev_stack_top); + return retval; } - } - return retval; - } + /** + * Parses any of a group of 'value' style ast_node groups from input + */ + bool Value() { + if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container()) { + return true; + } + else { + return false; + } + } - /** - * Top level parser, starts parsing of all known parses - */ - bool Statements() { - bool retval = false; + bool Operator_Helper(size_t t_precedence) { + for (size_t i = 0; i < m_operator_matches[t_precedence].size(); ++i) { + if (Symbol(m_operator_matches[t_precedence][i].c_str(), true)) { + return true; + } + } + return false; + } - bool has_more = true; - bool saw_eol = true; + bool Operator(size_t t_precedence = 0) { + bool retval = false; - while (has_more) { - has_more = false; - int prev_line = m_line; - int prev_col = m_col; - if (Def()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Try()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (If()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (While()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (For()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Return()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Break()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Equation()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } - else if (Block()) { - has_more = true; - retval = true; - saw_eol = true; - } - else { - has_more = false; - } - } + size_t prev_stack_top = m_match_stack.size(); - return retval; - } + if (t_precedence < m_operators.size()) { + if (Operator(t_precedence+1)) { + retval = true; + if (Operator_Helper(t_precedence)) { + do { + if (!Operator(t_precedence+1)) { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + } while (Operator_Helper(t_precedence)); - /** - * Parses the given input string, tagging parsed ast_nodes with the given m_filename. - */ - bool parse(const std::string &t_input, const std::string &t_fname) { - m_input_pos = t_input.begin(); - m_input_end = t_input.end(); - m_line = 1; - m_col = 1; - m_filename = boost::shared_ptr(new std::string(t_fname)); + switch (m_operators[t_precedence]) { + case(AST_Node_Type::Comparison) : + build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Dot_Access) : + build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Additive) : + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Multiplicative) : + build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Shift) : + build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Equality) : + build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_And) : + build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Xor) : + build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Or) : + build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Logical_And) : + build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Logical_Or) : + build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); + break; + default: + throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + } + } + } + } + else { + return Value(); + } - if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { - while ((m_input_pos != m_input_end) && (!Eol())) { - ++m_input_pos; + return retval; } - // TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) - } - if (Statements()) { - if (m_input_pos != m_input_end) { - throw Eval_Error("Unparsed input", File_Position(m_line, m_col), t_fname); + /** + * Reads a pair of values used to create a map initialization from input + */ + bool Map_Pair() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + std::string::const_iterator prev_pos = m_input_pos; + int prev_col = m_col; + + if (Operator()) { + if (Symbol(":")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; } - else { - build_match(AST_NodePtr(new File_AST_Node()), 0); - return true; + + /** + * Reads a pair of values used to create a range initialization from input + */ + bool Value_Range() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + std::string::const_iterator prev_pos = m_input_pos; + int prev_col = m_col; + + if (Operator()) { + if (Symbol("..")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; } - } - else { - return false; - } - } - }; + + /** + * Parses a string of binary equation operators + */ + bool Equation() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Operator()) { + retval = true; + if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || + Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || + Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || + Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { + if (!Equation()) { + throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); + } + } + + return retval; + } + + /** + * Top level parser, starts parsing of all known parses + */ + bool Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + has_more = false; + int prev_line = m_line; + int prev_col = m_col; + if (Def()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Try()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (If()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (While()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (For()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Return()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Break()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Equation()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } + else if (Block()) { + has_more = true; + retval = true; + saw_eol = true; + } + else { + has_more = false; + } + } + + return retval; + } + + /** + * Parses the given input string, tagging parsed ast_nodes with the given m_filename. + */ + bool parse(const std::string &t_input, const std::string &t_fname) { + m_input_pos = t_input.begin(); + m_input_end = t_input.end(); + m_line = 1; + m_col = 1; + m_filename = boost::shared_ptr(new std::string(t_fname)); + + if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { + while ((m_input_pos != m_input_end) && (!Eol())) { + ++m_input_pos; + } + // TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) + } + + if (Statements()) { + if (m_input_pos != m_input_end) { + throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); + } + else { + build_match(AST_NodePtr(new eval::File_AST_Node()), 0); + return true; + } + } + else { + return false; + } + } + }; + } } #endif /* CHAISCRIPT_PARSER_HPP_ */ diff --git a/include/chaiscript/language/chaiscript_prelude.hpp b/include/chaiscript/language/chaiscript_prelude.hpp index 7dcc0c94..ac05bc28 100644 --- a/include/chaiscript/language/chaiscript_prelude.hpp +++ b/include/chaiscript/language/chaiscript_prelude.hpp @@ -1,6 +1,6 @@ // This file is distributed under the BSD License. // See "license.txt" for details. -// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 9371687d..27489302 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -1,5 +1,11 @@ -#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP__ -#define CHAISCRIPT_UTILITY_UTILITY_HPP__ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) +// and Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ +#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #include "../chaiscript.hpp" #include diff --git a/samples/example.cpp b/samples/example.cpp index e8029822..51ef10aa 100644 --- a/samples/example.cpp +++ b/samples/example.cpp @@ -45,7 +45,7 @@ struct System void add_callback(const std::string &t_name, const chaiscript::Proxy_Function &t_func) { - m_callbacks[t_name] = chaiscript::functor(t_func); + m_callbacks[t_name] = chaiscript::dispatch::functor(t_func); } @@ -115,7 +115,7 @@ int main(int /*argc*/, char * /*argv*/[]) { //Call bound version of do_callbacks chai("do_callbacks()"); - boost::function caller = chai.functor("fun() { system.do_callbacks(\"From Functor\"); }"); + boost::function caller = chai.eval >("fun() { system.do_callbacks(\"From Functor\"); }"); caller(); @@ -139,7 +139,7 @@ int main(int /*argc*/, char * /*argv*/[]) { //To do: Add examples of handling Boxed_Values directly when needed //Creating a functor on the stack and using it immediatly - int x = chai.functor("fun (x, y) { return x + y; }")(5, 6); + int x = chai.eval >("fun (x, y) { return x + y; }")(5, 6); log("Functor test output", boost::lexical_cast(x)); @@ -163,9 +163,9 @@ int main(int /*argc*/, char * /*argv*/[]) { chai.add(fun(&bound_log, std::string("Msg")), "BoundFun"); //Dynamic objects test - chai.add(chaiscript::Proxy_Function(new detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); - chai.add(chaiscript::Proxy_Function(new detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); - chai.add(fun(boost::function(boost::bind(&detail::Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr"); + chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); + chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); + chai.add(fun(boost::function(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr"); chai.eval("var x = TestType()"); // chai.eval("x.attr = \"hi\""); diff --git a/src/main.cpp b/src/main.cpp index 5acdf2a8..bc833322 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,10 +52,10 @@ void version(int){ std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl; } -bool throws_exception(const chaiscript::Proxy_Function &f) +bool throws_exception(const boost::function &f) { try { - chaiscript::functor(f)(); + f(); } catch (...) { return true; } @@ -63,6 +63,17 @@ bool throws_exception(const chaiscript::Proxy_Function &f) return false; } +chaiscript::exception::eval_error get_eval_error(const boost::function &f) +{ + try { + f(); + } catch (const chaiscript::exception::eval_error &e) { + return e; + } + + throw std::runtime_error("no exception throw"); +} + std::string get_next_command() { std::string retval("quit"); if ( ! std::cin.eof() ) { @@ -102,19 +113,19 @@ void interactive(chaiscript::ChaiScript& chai) //Then, we try to print the result of the evaluation to the user if (!val.get_type_info().bare_equal(chaiscript::user_type())) { try { - chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val); + std::cout << chai.eval >("to_string")(val) << std::endl; } catch (...) {} //If we can't, do nothing } } - catch (chaiscript::Eval_Error &ee) { + catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.what(); if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; } std::cout << std::endl; } - catch (std::exception &e) { + catch (const std::exception &e) { std::cout << e.what(); std::cout << std::endl; } @@ -158,6 +169,7 @@ int main(int argc, char *argv[]) chai.add(chaiscript::fun(&help), "help"); chai.add(chaiscript::fun(&version), "version"); chai.add(chaiscript::fun(&throws_exception), "throws_exception"); + chai.add(chaiscript::fun(&get_eval_error), "get_eval_error"); for (int i = 0; i < argc; ++i) { if ( i == 0 && argc > 1 ) { @@ -205,13 +217,17 @@ int main(int argc, char *argv[]) case eFile : val = chai.eval_file(arg); break; } } - catch (chaiscript::Eval_Error &ee) { + catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.what(); if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; - for (unsigned int j = 1; j < ee.call_stack.size(); ++j) { - std::cout << std::endl; - std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; + for (size_t j = 1; j < ee.call_stack.size(); ++j) { + if (ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::Block + && ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::File) + { + std::cout << std::endl; + std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; + } } } std::cout << std::endl; diff --git a/src/reflection.cpp b/src/reflection.cpp index d5fc6cb6..98f0dbb0 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -14,7 +14,8 @@ bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) { - boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + boost::shared_ptr pf + = boost::dynamic_pointer_cast(t_pf); if (pf) { return pf->get_parse_tree(); @@ -25,7 +26,8 @@ bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) { - boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + boost::shared_ptr pf + = boost::dynamic_pointer_cast(t_pf); if (pf) { if (pf->get_parse_tree()) @@ -50,6 +52,13 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); + CHAISCRIPT_CLASS( m, + chaiscript::exception::eval_error, + , + ((reason)) + ((call_stack)) + ); + CHAISCRIPT_CLASS( m, chaiscript::File_Position, (chaiscript::File_Position()) @@ -60,7 +69,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect CHAISCRIPT_CLASS( m, chaiscript::AST_Node, - (chaiscript::AST_Node (const std::string &, int, const boost::shared_ptr &)), + , ((text)) ((identifier)) ((filename)) @@ -68,11 +77,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect ((end)) ((internal_to_string)) ((children)) + ((replace_child)) ); CHAISCRIPT_CLASS( m, - chaiscript::ChaiScript_Parser, - (chaiscript::ChaiScript_Parser ()), + chaiscript::parser::ChaiScript_Parser, + (chaiscript::parser::ChaiScript_Parser ()), ((parse)) ((ast)) ); diff --git a/unittests/assign_const.chai b/unittests/assign_const.chai new file mode 100644 index 00000000..ff6a8c3d --- /dev/null +++ b/unittests/assign_const.chai @@ -0,0 +1,2 @@ +assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } ); +assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } ); diff --git a/unittests/dynamic_object_test.cpp b/unittests/dynamic_object_test.cpp index 251716f2..8383e039 100644 --- a/unittests/dynamic_object_test.cpp +++ b/unittests/dynamic_object_test.cpp @@ -19,7 +19,7 @@ int main() chai("attr bob::z; def bob::bob() { this.z = 10 }; var x = bob()"); - chaiscript::Dynamic_Object &mydo = chai.eval("x"); + chaiscript::dispatch::Dynamic_Object &mydo = chai.eval("x"); assert_equal(mydo.get_type_name(), "bob"); diff --git a/unittests/eval_error.chai b/unittests/eval_error.chai new file mode 100644 index 00000000..d63ad759 --- /dev/null +++ b/unittests/eval_error.chai @@ -0,0 +1,39 @@ +load_module("reflection") + +def deep() +{ + try { + } catch { + + } finally { + if (2) + { + } + + } +} + +def func() +{ + deep(); +} + +def doing() +{ + for (var i = 0; i < 10; ++i) + { + func(); + } +} + +def while_doing() +{ + while (true) + { + doing(); + } +} + +var f = fun() { while_doing(); } + +assert_equal(get_eval_error(f).call_stack.size(), 16) diff --git a/unittests/functor_creation_test.cpp b/unittests/functor_creation_test.cpp index ada73693..6578a6d5 100644 --- a/unittests/functor_creation_test.cpp +++ b/unittests/functor_creation_test.cpp @@ -7,10 +7,20 @@ int main() chai.eval("def func() { print(\"Hello World\"); } "); - boost::function f = chai.functor("func"); - + boost::function f = chai.eval >("func"); f(); - return EXIT_SUCCESS; + if (chai.eval >("to_string")(6) != "6") + { + return EXIT_FAILURE; + } + + if (chai.eval >("to_string")(chaiscript::var(6)) == "6") + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } diff --git a/unittests/reflection_test.chai b/unittests/reflection_test.chai index 7841f238..88b39ccc 100644 --- a/unittests/reflection_test.chai +++ b/unittests/reflection_test.chai @@ -8,7 +8,11 @@ assert_equal(eval(a), 7) var childs := a.children.front().children var node := childs[0] -node.text = "9" +var parser2 := ChaiScript_Parser() +parser2.parse("9", "INPUT") + + +a.children.front().replace_child(childs[0], parser2.ast()) assert_equal(eval(a), 13) assert_equal(node.filename, "INPUT") diff --git a/unittests/unit_test.inc b/unittests/unit_test.inc index fbd6633d..d746e7bf 100644 --- a/unittests/unit_test.inc +++ b/unittests/unit_test.inc @@ -10,6 +10,24 @@ def assert_equal(x, y) } } +def assert_false(f) +{ + if (f) + { + print("assert_false failure"); + exit(-1); + } +} + +def assert_true(f) +{ + if (!f) + { + print("assert_false failure"); + exit(-1); + } +} + def assert_not_equal(x, y) { if (!(x == y))