From 9dd9ffec4676b28b08a46bec19c6a82606b111f0 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 15 Mar 2011 09:42:33 -0600 Subject: [PATCH 01/13] Update copyright information for 2011 --- include/chaiscript/chaiscript.hpp | 2 +- include/chaiscript/chaiscript_threading.hpp | 6 ++++++ include/chaiscript/dispatchkit/bad_boxed_cast.hpp | 2 +- include/chaiscript/dispatchkit/bind_first.hpp | 2 +- include/chaiscript/dispatchkit/bootstrap.hpp | 2 +- include/chaiscript/dispatchkit/bootstrap_stl.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast_helper.hpp | 2 +- include/chaiscript/dispatchkit/boxed_pod_value.hpp | 2 +- include/chaiscript/dispatchkit/boxed_value.hpp | 2 +- include/chaiscript/dispatchkit/dispatchkit.hpp | 2 +- include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp | 6 ++++++ include/chaiscript/dispatchkit/dynamic_object.hpp | 6 ++++++ include/chaiscript/dispatchkit/function_call_detail.hpp | 2 +- include/chaiscript/dispatchkit/handle_return.hpp | 2 +- include/chaiscript/dispatchkit/operators.hpp | 6 ++++++ include/chaiscript/dispatchkit/proxy_constructors.hpp | 2 +- include/chaiscript/dispatchkit/proxy_functions.hpp | 2 +- include/chaiscript/dispatchkit/proxy_functions_detail.hpp | 2 +- include/chaiscript/dispatchkit/register_function.hpp | 2 +- include/chaiscript/dispatchkit/type_info.hpp | 2 +- include/chaiscript/language/chaiscript_common.hpp | 2 +- include/chaiscript/language/chaiscript_engine.hpp | 2 +- include/chaiscript/language/chaiscript_eval.hpp | 2 +- include/chaiscript/language/chaiscript_parser.hpp | 2 +- include/chaiscript/language/chaiscript_prelude.hpp | 2 +- include/chaiscript/utility/utility.hpp | 6 ++++++ 27 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 4cf40887..10576ce3 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.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/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index cebb40f7..ff3689f5 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_ diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 1070ecdb..22f6e6a8 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 diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 7c0a338c..9a8a95df 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 diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index ceb84413..29d1b3bd 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 diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 82b9ba5f..5aed07f4 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.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_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 6cd137c3..0abfcff2 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 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..42d7faeb 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 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..4fe14348 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 diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 5bbb6fe7..0425286b 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_ diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index fdccbbac..732bd8a3 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_ diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index e9f977cb..61eebc83 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_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 diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index 5932e742..ba2b381a 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 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..ed3a7c9c 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 diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index c8ec5493..3b1e147e 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 diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 7b426169..036ad5e9 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 diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 6fa2bb4f..fbd4fc29 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 diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 15a224a1..001bf9a7 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 diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index be6c9662..1dfb9470 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 diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 554ef39a..36beb009 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 diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 66655c39..872d1353 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 diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 2fcc3016..9d18c290 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 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..7409acba 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.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_UTILITY_UTILITY_HPP__ #define CHAISCRIPT_UTILITY_UTILITY_HPP__ From 637164e457dec5c5adadde46d5fe6f02b472fe9c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 15 Mar 2011 17:35:14 -0600 Subject: [PATCH 02/13] Move around some namespaces for documentation purposes. Fix problems with building on clang 2.8. Remove unneeded function for get_engine() and fix functor<> calls that take a Boxed_Value --- .../chaiscript/dispatchkit/dispatchkit.hpp | 63 +- .../dispatchkit/function_call_detail.hpp | 3 +- .../dispatchkit/proxy_functions.hpp | 40 +- .../dispatchkit/proxy_functions_detail.hpp | 55 +- .../chaiscript/language/chaiscript_engine.hpp | 14 +- .../chaiscript/language/chaiscript_eval.hpp | 2441 +++++++++-------- .../chaiscript/language/chaiscript_parser.hpp | 283 +- src/main.cpp | 2 +- unittests/functor_creation_test.cpp | 14 +- 9 files changed, 1478 insertions(+), 1437 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 4fe14348..88e097bd 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -257,37 +257,48 @@ namespace chaiscript }; - /** - * Exception thrown in the case that a multi method dispatch fails - * because no matching function was found - * at runtime due to either an arity_error, a guard_error or a bad_boxed_cast - * exception - */ - struct reserved_word_error : std::runtime_error + 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 { - } - - virtual ~global_non_const() throw() {} - }; + public: + global_non_const() throw() + : std::runtime_error("a global object must be const") + { + } + virtual ~global_non_const() throw() {} + }; + } /** * Main class for the dispatchkit. Handles management @@ -377,7 +388,7 @@ namespace chaiscript validate_object_name(name); if (!obj.is_const()) { - throw global_non_const(); + throw exception::global_non_const(); } #ifndef CHAISCRIPT_NO_THREADS @@ -909,7 +920,7 @@ namespace chaiscript if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) { - throw reserved_word_error(name); + throw exception::reserved_word_error(name); } } diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 61eebc83..d6798c84 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -6,7 +6,7 @@ #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)) @@ -25,6 +25,7 @@ namespace chaiscript { namespace detail { + /** * Internal helper class for handling the return * value of a build_function_caller diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 3b1e147e..825b0979 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -324,7 +324,7 @@ namespace chaiscript 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) + 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())); } @@ -569,26 +569,30 @@ namespace chaiscript 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 + namespace exception { - dispatch_error() throw() - : std::runtime_error("No matching function to dispatch to") + /** + * 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":"")) - { - } + 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() {} - }; + virtual ~dispatch_error() throw() {} + }; + } /** * Take a vector of functions and a vector of parameters. Attempt to execute @@ -617,7 +621,7 @@ namespace chaiscript ++begin; } - throw dispatch_error(plist.empty()?false:plist[0].is_const()); + throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); } /** diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 036ad5e9..8402959b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -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/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 36beb009..5526f568 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -298,6 +298,13 @@ namespace chaiscript } } + /** + * Returns the current evaluation m_engine + */ + Dispatch_Engine &get_eval_engine() { + return m_engine; + } + public: ChaiScript(const std::vector &t_modulepaths = std::vector(), @@ -481,13 +488,6 @@ namespace chaiscript } - /** - * Returns the current evaluation m_engine - */ - Dispatch_Engine &get_eval_engine() { - return m_engine; - } - /** * Helper function for loading a file */ diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 872d1353..1382c60f 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -42,761 +42,691 @@ namespace chaiscript } - 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(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)); + retval = this->children[0]->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]); + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); 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 { - plb << this->children[1]->children[i]->eval(t_ss); + retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss)); + } + catch(const exception::dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); } catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); + ee.call_stack.push_back(this->children[i+1]); throw; } } + + return retval; } - 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); + 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) { } - 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(...) { - 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); + 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 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) { + 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 { - plb << this->children[1]->children[i]->eval(t_ss); + return t_ss.get_object(this->text); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); - throw; + catch (std::exception &) { + throw Eval_Error("Can not find object: " + this->text); } } } + }; - try { - Boxed_Value fn = this->children[0]->eval(t_ss); + 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() {} + }; - try { - return (*boxed_cast(fn))(plb); - } - catch(const dispatch_error &e){ - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); - } - catch(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 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; - 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 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 == "=") { + 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 { - Boxed_Value lhs = this->children[i]->eval(t_ss); - - try { - if (lhs.is_undef()) { - retval = t_ss.call_function("clone", retval); - retval.clear_dependencies(); - } - - 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 dispatch_error &){ - throw Eval_Error("Can not clone right hand side of equation"); - } + plb << this->children[1]->children[i]->eval(t_ss); } catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } - } - else if (this->children[i+1]->text == ":=") { - try { - 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"); - } - } - 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]); + ee.call_stack.push_back(this->children[1]->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); - } + Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); + Dispatch_Engine::Stack new_stack = t_ss.new_stack(); - }; - - 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) { - try { - 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(); + Boxed_Value fn = this->children[0]->eval(t_ss); try { t_ss.set_stack(new_stack); - retval = t_ss.call_function(fun_name, plb); + const Boxed_Value &retval = (*boxed_cast(fn))(plb); t_ss.set_stack(prev_stack); + return retval; } - catch(const dispatch_error &e){ + catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what())); + throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } catch(Return_Value &rv) { t_ss.set_stack(prev_stack); - retval = rv.retval; + return 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) { + } + 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(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 { + 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); + } + catch(const exception::dispatch_error &e){ + throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } + catch(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 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(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 { - 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 '[]' "); + Boxed_Value lhs = this->children[i]->eval(t_ss); + + try { + if (lhs.is_undef()) { + retval = t_ss.call_function("clone", retval); + retval.clear_dependencies(); + } + + try { + retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); + } + catch(const exception::dispatch_error &){ + throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); + } + } + catch(const exception::dispatch_error &){ + throw Eval_Error("Can not clone right hand side of equation"); + } } catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[i]->children[j]); + ee.call_stack.push_back(this->children[i]); + throw; + } + } + else if (this->children[i+1]->text == ":=") { + try { + 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"); + } + } + 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 exception::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; } + }; - 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) { + 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 { - const Boxed_Value &retval = this->children[i]->eval(t_ss); - - if (i + 1 == num_children) - { - t_ss.pop_scope(); - return retval; - } + t_ss.add_object(this->children[0]->text, Boxed_Value()); } - catch (const chaiscript::Return_Value &) { - t_ss.pop_scope(); - throw; + catch (const exception::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[i]); - t_ss.pop_scope(); + ee.call_stack.push_back(this->children[0]); 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 { + for (size_t i = 1; i < this->children.size(); ++i) { try { - this->children[1]->eval(t_ss); + retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; + catch(std::out_of_range &) { + throw Eval_Error("Out of bounds exception"); } - - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); + catch(const exception::dispatch_error &){ + throw Eval_Error("Can not find appropriate array lookup '[]' "); } - 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(); + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); 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; + return retval; } + }; - if (cond) { + 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 { - return this->children[1]->eval(t_ss); + retval = this->children[0]->eval(t_ss); } catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[1]); + ee.call_stack.push_back(this->children[0]); 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 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) { + + 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) { try { - return this->children[i+2]->eval(t_ss); + plb << this->children[i]->children[1]->children[j]->eval(t_ss); } catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+2]); + 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 exception::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 exception::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; } } } - 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) { } + virtual ~Quoted_String_AST_Node() {} + virtual Boxed_Value eval(Dispatch_Engine &){ + return const_var(this->text); + } - 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; + }; - t_ss.new_scope(); + 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])); + } - try { - if (this->children.size() == 4) { - try { - this->children[0]->eval(t_ss); + }; + + 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); } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]); + + } + 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 (const exception::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 { - cond = boxed_cast(this->children[1]->eval(t_ss)); + 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]); @@ -804,36 +734,66 @@ namespace chaiscript } } 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; + 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 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) { + try { + return this->children[i+2]->eval(t_ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+2]); + throw; + } + } + } + i = i + 3; + } } } + + return Boxed_Value(false); } - catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); - } - while (cond) { + + }; + + 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; + + t_ss.new_scope(); + try { if (this->children.size() == 4) { try { - this->children[3]->eval(t_ss); + this->children[0]->eval(t_ss); } catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[3]); - throw; - } - - try { - this->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[2]); + ee.call_stack.push_back(this->children[0]); throw; } @@ -846,22 +806,6 @@ namespace chaiscript } } else { - try { - this->children[2]->eval(t_ss); - } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[2]); - throw; - } - - 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)); } @@ -876,251 +820,335 @@ namespace chaiscript t_ss.pop_scope(); throw Eval_Error("For condition not boolean"); } - catch (Break_Loop &) { - cond = 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) { + while (cond) { try { - vec.push_back(this->children[0]->children[i]->eval(t_ss)); + 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; + } + + 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; + } + + 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 (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + t_ss.pop_scope(); + throw; + } + } } - catch(Eval_Error &ee) { - ee.call_stack.push_back(this->children[0]->children[i]); - throw; - } - } - } - - 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 { - 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); - } - 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; - } - } - else { - throw 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 { - 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(); - } - }; - - 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 { - 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(Dispatch_Engine &){ - throw 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 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]); + catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw; + throw Eval_Error("For condition not boolean"); + } + catch (Break_Loop &) { + cond = false; } } t_ss.pop_scope(); - throw; + return Boxed_Value(); } - 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; + }; + + 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) { + try { + 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; + } + } } - 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 + 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 { - retval = catch_block->children[0]->eval(t_ss); + 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(catch_block->children[0]); + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]->children[i]); 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); + return const_var(retval); + } + catch (const exception::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; + } + } + else { + throw 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 { + 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(catch_block->children[1]); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; + } + } + 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 { + 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(Dispatch_Engine &){ + throw 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 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 exception::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; } - - break; } - else if (catch_block->children.size() == 3) { - //Variable capture, no guards - t_ss.add_object(catch_block->children[0]->text, except); + t_ss.pop_scope(); + throw; + } + catch (const std::exception &e) { + Boxed_Value except = Boxed_Value(boost::ref(e)); - bool guard; - try { - guard = boxed_cast(catch_block->children[1]->eval(t_ss)); - } catch (const exception::bad_boxed_cast &) { + 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); @@ -1132,75 +1160,79 @@ namespace chaiscript } } t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); + throw Eval_Error("Internal error: catch block size unrecognized"); } - if (guard) { + } + } + 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[2]->eval(t_ss); + retval = catch_block->children[0]->eval(t_ss); } catch (Eval_Error &ee) { - ee.call_stack.push_back(catch_block->children[2]); + ee.call_stack.push_back(catch_block->children[0]); throw; } break; } - } - else { - if (this->children.back()->identifier == AST_Node_Type::Finally) { + else if (catch_block->children.size() == 2) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); try { - this->children.back()->children[0]->eval(t_ss); + retval = catch_block->children[1]->eval(t_ss); } catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); + ee.call_stack.push_back(catch_block->children[1]); 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() == 3) { + //Variable capture, no guards + t_ss.add_object(catch_block->children[0]->text, except); - 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; - } + 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; + } + } - 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)); + 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; + } } - catch (const exception::bad_boxed_cast &) { + else { if (this->children.back()->identifier == AST_Node_Type::Finally) { try { this->children.back()->children[0]->eval(t_ss); @@ -1211,45 +1243,29 @@ namespace chaiscript throw; } } - t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); + throw Eval_Error("Internal error: catch block size unrecognized"); } - 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 (...) { + 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) { try { - this->children.back()->children[0]->eval(t_ss); + retval = this->children.back()->children[0]->eval(t_ss); } catch (Eval_Error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); @@ -1257,258 +1273,245 @@ namespace chaiscript throw; } } + t_ss.pop_scope(); - throw; + + return retval; } - if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - retval = 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(); + 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() {} + }; - return retval; - } + 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(Dispatch_Engine &t_ss){ - 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() {} - }; + std::vector t_param_names; + AST_NodePtr guardnode; - 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() {} - }; + //The first param of a method is always the implied this ptr. + t_param_names.push_back("this"); - 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){ - - 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 { - //no parameters - - if (this->children.size() > 3) { - guardnode = this->children[2]; - } - } - - 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)); - } - - 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); + 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 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 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 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); - } - } - } - 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; - } - - 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 { + boost::optional ti; try { - retval = this->children[i+1]->eval(t_ss); + ti = t_ss.get_type(class_name); + } catch (const std::range_error &) { + // No biggie, the type name is just not known } - catch (Eval_Error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; + 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); + + } + } + catch (const exception::reserved_word_error &e) { + throw Eval_Error("Reserved word used as method name '" + e.word() + "'"); + } + return Boxed_Value(); + } + + }; + + 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); + + } + catch (const exception::reserved_word_error &) { + throw 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(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); } } } + 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(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) { + retval = Boxed_Value(true); + } + else { + try { + retval = this->children[i+1]->eval(t_ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + } + } + return retval; + } + + }; + } } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 9d18c290..de8b3933 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -16,20 +16,23 @@ 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 - }; + namespace detail + { + 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 { @@ -40,7 +43,7 @@ namespace chaiscript std::string m_singleline_comment; boost::shared_ptr m_filename; std::vector m_match_stack; - bool m_alphabet[max_alphabet][lengthof_alphabet]; + bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; std::vector > m_operator_matches; std::vector m_operators; @@ -122,55 +125,55 @@ namespace chaiscript 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 ++ ) { + for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { + for ( int a = 0 ; a < detail::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; + 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; - 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 = '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[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[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[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; } + 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[x_alphabet]['x']=true; - m_alphabet[x_alphabet]['X']=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[bin_alphabet][c]=true; } - m_alphabet[b_alphabet]['b']=true; - m_alphabet[b_alphabet]['B']=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[id_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[id_alphabet][c]=true; } - m_alphabet[id_alphabet]['_'] = 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[white_alphabet][' ']=true; - m_alphabet[white_alphabet]['\t']=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,Alphabet a) { return m_alphabet[a][c]; } + bool char_in_alphabet(unsigned char c, detail::Alphabet a) { return m_alphabet[a][c]; } /** * Prints the parsed ast_nodes as a tree @@ -298,7 +301,7 @@ namespace chaiscript bool SkipWS() { bool retval = false; while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,white_alphabet) ) { + if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) ) { ++m_input_pos; ++m_col; retval = true; @@ -320,17 +323,17 @@ namespace chaiscript bool retval = false; std::string::const_iterator start = m_input_pos; - if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { - while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { + 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,int_alphabet)) { + 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,int_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { ++m_input_pos; ++m_col; } @@ -353,12 +356,12 @@ namespace chaiscript ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,x_alphabet) ) { + 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,hex_alphabet)) { + 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,hex_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { ++m_input_pos; ++m_col; } @@ -386,12 +389,12 @@ namespace chaiscript ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,b_alphabet) ) { + 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,bin_alphabet) ) { + 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,bin_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { ++m_input_pos; ++m_col; } @@ -423,7 +426,7 @@ namespace chaiscript 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 (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); @@ -432,7 +435,7 @@ namespace chaiscript 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)); + 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; } @@ -451,13 +454,13 @@ namespace chaiscript 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)); + 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 Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col)); + 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; } @@ -470,11 +473,11 @@ namespace chaiscript 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)); + 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 Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + 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; @@ -491,9 +494,9 @@ namespace chaiscript */ bool Id_() { bool retval = false; - if (has_more_input() && char_in_alphabet(*m_input_pos,id_alphabet)) { + 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,keyword_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { ++m_input_pos; ++m_col; } @@ -544,13 +547,13 @@ namespace chaiscript 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)); + 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 Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + 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; } @@ -583,7 +586,7 @@ namespace chaiscript } 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)); + 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; } @@ -658,23 +661,23 @@ namespace chaiscript 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)); + 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 Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + 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 Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::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)); + 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 Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + 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; @@ -690,28 +693,28 @@ namespace chaiscript 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)); + 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 Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + 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 Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + 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 Arg_List_AST_Node()), arg_stack_top); + build_match(AST_NodePtr(new eval::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 eval::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 eval::Arg_List_AST_Node()), ev_stack_top); - build_match(AST_NodePtr(new Fun_Call_AST_Node()), tostr_stack_top); + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); } else { throw Eval_Error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); @@ -758,16 +761,16 @@ namespace chaiscript } } if (is_interpolated) { - AST_NodePtr plus(new Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + 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 Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + 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 Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::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)); + 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; @@ -859,7 +862,7 @@ namespace chaiscript is_escaped = false; } } - 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)); + 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; } @@ -898,7 +901,7 @@ namespace chaiscript int prev_line = m_line; if (Char_(t_c)) { 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::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; } @@ -941,7 +944,7 @@ namespace chaiscript 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 ( 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; @@ -950,7 +953,7 @@ namespace chaiscript 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)); + 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; @@ -989,7 +992,7 @@ namespace chaiscript 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)) { + 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; @@ -998,7 +1001,7 @@ namespace chaiscript 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)); + 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); } @@ -1038,7 +1041,7 @@ namespace chaiscript 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)); + 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; } @@ -1067,7 +1070,7 @@ namespace chaiscript } } while (retval && Char(',')); } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); } return retval; @@ -1083,7 +1086,7 @@ namespace chaiscript if (Value_Range()) { retval = true; - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); } else if (Map_Pair()) { retval = true; @@ -1096,7 +1099,7 @@ namespace chaiscript } } while (retval && Char(',')); } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); } else if (Operator()) { retval = true; @@ -1109,7 +1112,7 @@ namespace chaiscript } } while (retval && Char(',')); } - build_match(AST_NodePtr(new Arg_List_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); } return retval; @@ -1140,7 +1143,7 @@ namespace chaiscript 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); + build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); } return retval; @@ -1201,10 +1204,10 @@ namespace chaiscript } if (is_method) { - build_match(AST_NodePtr(new Method_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); } else { - build_match(AST_NodePtr(new Def_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); } if (is_annotated) { @@ -1254,7 +1257,7 @@ namespace chaiscript if (!Block()) { throw Eval_Error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Catch_AST_Node()), catch_stack_top); + build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); has_matches = true; } } @@ -1267,10 +1270,10 @@ namespace chaiscript if (!Block()) { throw Eval_Error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Finally_AST_Node()), finally_stack_top); + build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); } - build_match(AST_NodePtr(new Try_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); } return retval; @@ -1334,7 +1337,7 @@ namespace chaiscript } } - build_match(AST_NodePtr(new If_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); } return retval; @@ -1365,7 +1368,7 @@ namespace chaiscript 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); + build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); } return retval; @@ -1410,7 +1413,7 @@ namespace chaiscript 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); + build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); } return retval; @@ -1432,7 +1435,7 @@ namespace chaiscript throw Eval_Error("Incomplete block", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Block_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); } return retval; @@ -1450,7 +1453,7 @@ namespace chaiscript retval = true; Operator(); - build_match(AST_NodePtr(new Return_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); } return retval; @@ -1467,7 +1470,7 @@ namespace chaiscript if (Keyword("break")) { retval = true; - build_match(AST_NodePtr(new Break_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); } return retval; @@ -1496,7 +1499,7 @@ namespace chaiscript throw Eval_Error("Incomplete function call", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Fun_Call_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); } else if (Char('[')) { has_more = true; @@ -1505,7 +1508,7 @@ namespace chaiscript throw Eval_Error("Incomplete array access", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Array_Call_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); } } } @@ -1528,7 +1531,7 @@ namespace chaiscript throw Eval_Error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Var_Decl_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); } else if (Keyword("attr")) { retval = true; @@ -1544,7 +1547,7 @@ namespace chaiscript } - build_match(AST_NodePtr(new Attr_Decl_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); } return retval; @@ -1584,17 +1587,17 @@ namespace chaiscript } 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::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 Inline_Map_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); } else { - build_match(AST_NodePtr(new Inline_Array_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); } } else { - build_match(AST_NodePtr(new Inline_Array_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); } } @@ -1616,7 +1619,7 @@ namespace chaiscript throw Eval_Error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } else if (Symbol("--", true)) { retval = true; @@ -1625,7 +1628,7 @@ namespace chaiscript throw Eval_Error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } else if (Char('-', true)) { retval = true; @@ -1634,7 +1637,7 @@ namespace chaiscript throw Eval_Error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } else if (Char('+', true)) { retval = true; @@ -1643,7 +1646,7 @@ namespace chaiscript throw Eval_Error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } else if (Char('!', true)) { retval = true; @@ -1652,7 +1655,7 @@ namespace chaiscript throw Eval_Error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } else if (Char('~', true)) { retval = true; @@ -1661,7 +1664,7 @@ namespace chaiscript throw Eval_Error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Prefix_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } return retval; @@ -1708,37 +1711,37 @@ namespace chaiscript switch (m_operators[t_precedence]) { case(AST_Node_Type::Comparison) : - build_match(AST_NodePtr(new Comparison_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::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); + build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); break; case(AST_Node_Type::Additive) : - build_match(AST_NodePtr(new Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); break; case(AST_Node_Type::Multiplicative) : - build_match(AST_NodePtr(new Multiplicative_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); break; case(AST_Node_Type::Shift) : - build_match(AST_NodePtr(new Shift_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); break; case(AST_Node_Type::Equality) : - build_match(AST_NodePtr(new Equality_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::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); + 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 Bitwise_Xor_AST_Node()), prev_stack_top); + 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 Bitwise_Or_AST_Node()), prev_stack_top); + 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 Logical_And_AST_Node()), prev_stack_top); + 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 Logical_Or_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::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); @@ -1770,7 +1773,7 @@ namespace chaiscript throw Eval_Error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Map_Pair_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); } else { m_input_pos = prev_pos; @@ -1801,7 +1804,7 @@ namespace chaiscript throw Eval_Error("Incomplete value range", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Value_Range_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); } else { m_input_pos = prev_pos; @@ -1833,7 +1836,7 @@ namespace chaiscript throw Eval_Error("Incomplete equation", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new Equation_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); } } @@ -1957,7 +1960,7 @@ namespace chaiscript throw Eval_Error("Unparsed input", File_Position(m_line, m_col), t_fname); } else { - build_match(AST_NodePtr(new File_AST_Node()), 0); + build_match(AST_NodePtr(new eval::File_AST_Node()), 0); return true; } } diff --git a/src/main.cpp b/src/main.cpp index 5acdf2a8..dbffe039 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -102,7 +102,7 @@ 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.functor("to_string")(val) << std::endl; } catch (...) {} //If we can't, do nothing } diff --git a/unittests/functor_creation_test.cpp b/unittests/functor_creation_test.cpp index ada73693..432ea551 100644 --- a/unittests/functor_creation_test.cpp +++ b/unittests/functor_creation_test.cpp @@ -8,9 +8,19 @@ int main() chai.eval("def func() { print(\"Hello World\"); } "); boost::function f = chai.functor("func"); - f(); - return EXIT_SUCCESS; + if (chai.functor("to_string")(6) != "6") + { + return EXIT_FAILURE; + } + + if (chai.functor("to_string")(chaiscript::var(6)) == "6") + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } From cd8bead54a9d6185c462f1e53fa17d35cd345bba Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 24 Mar 2011 09:23:05 -0600 Subject: [PATCH 03/13] Further namespace reorganization and cleanup to limit to the user the most important aspect of the API and make documenation easier. --- include/chaiscript/dispatchkit/boxed_cast.hpp | 2 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 4 +- .../dispatchkit/dynamic_cast_conversion.hpp | 40 +- .../dispatchkit/proxy_functions.hpp | 75 +- .../chaiscript/language/chaiscript_common.hpp | 92 +- .../chaiscript/language/chaiscript_engine.hpp | 388 +- .../chaiscript/language/chaiscript_eval.hpp | 204 +- .../chaiscript/language/chaiscript_parser.hpp | 3477 +++++++++-------- src/main.cpp | 6 +- src/reflection.cpp | 4 +- 10 files changed, 2156 insertions(+), 2136 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 0abfcff2..242771b6 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -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/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 88e097bd..9467b584 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -201,7 +201,7 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms) const { - return dispatch(m_funcs.begin(), m_funcs.end(), params); + return detail::dispatch(m_funcs.begin(), m_funcs.end(), params); } private: @@ -647,7 +647,7 @@ namespace chaiscript { std::vector functions = get_function(t_name); - return dispatch(functions.begin(), functions.end(), params); + return detail::dispatch(functions.begin(), functions.end(), params); } Boxed_Value call_function(const std::string &t_name) const diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 0425286b..15ef49e3 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -254,29 +254,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/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 825b0979..4ec0bc9f 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -139,7 +139,7 @@ namespace chaiscript || (!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()) + || detail::dynamic_cast_converts(ti, bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) ) ) @@ -594,46 +594,49 @@ namespace chaiscript }; } - /** - * 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) + namespace detail { - while (begin != end) - { - try { - if ((*begin)->filter(plist)) + /** + * 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) { - return (*(*begin))(plist); + 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; } - } 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 + + throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); } - ++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(funcs.begin(), funcs.end(), plist); + /** + * 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(funcs.begin(), funcs.end(), plist); + } } } diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 1dfb9470..f2730e3b 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -108,59 +108,65 @@ namespace chaiscript - /** - * 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; + 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) : - 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, 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) - : std::runtime_error("Error: \"" + t_why + "\" "), + eval_error(const std::string &t_why) throw() + : std::runtime_error("Error: \"" + t_why + "\" "), reason(t_why) - {} + {} - virtual ~Eval_Error() throw() {} - }; + 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) - : std::runtime_error("File Not Found: " + t_filename) - { } + /** + * 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() {} - }; + virtual ~file_not_found_error() throw() {} + }; + } - /** - * Special type for returned values - */ - struct Return_Value { - Boxed_Value retval; + namespace detail + { + /** + * Special type for returned values + */ + struct Return_Value { + Boxed_Value retval; - Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } - }; + Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } + }; - /** - * Special type indicating a call to 'break' - */ - struct Break_Loop { - Break_Loop() { } - }; + /** + * 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 5526f568..af7ca14f 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -28,193 +28,199 @@ 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 get() - { - throw load_module_error("Loadable module support not available for your platform"); - } - }; + ModulePtr get() + { + throw exception::load_module_error("Loadable module support not available for your platform"); + } + }; #endif #endif - typedef boost::shared_ptr Loadable_Module_Ptr; + typedef boost::shared_ptr Loadable_Module_Ptr; + } class ChaiScript { #ifndef CHAISCRIPT_NO_THREADS @@ -223,7 +229,7 @@ namespace chaiscript #endif 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; @@ -238,7 +244,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); @@ -246,7 +252,7 @@ namespace chaiscript return Boxed_Value(); } } - catch (const Return_Value &rv) { + catch (const detail::Return_Value &rv) { return rv.retval; } } @@ -287,10 +293,10 @@ namespace chaiscript #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 @@ -305,6 +311,56 @@ namespace chaiscript 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(&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"); + } public: ChaiScript(const std::vector &t_modulepaths = std::vector(), @@ -398,7 +454,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"); @@ -419,7 +475,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 } @@ -429,7 +485,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) { @@ -441,7 +497,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); } /** @@ -455,7 +511,7 @@ namespace chaiscript 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); @@ -495,7 +551,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(); @@ -513,56 +569,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 1382c60f..2718c238 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -28,10 +28,10 @@ namespace chaiscript Boxed_Value retval(t_node->eval(t_ss)); t_ss.pop_scope(); return retval; - } catch (const Return_Value &rv) { + } catch (const detail::Return_Value &rv) { t_ss.pop_scope(); return rv.retval; - } catch (Eval_Error &ee) { + } catch (exception::eval_error &ee) { ee.call_stack.push_back(t_node); t_ss.pop_scope(); throw; @@ -55,7 +55,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -65,9 +65,9 @@ namespace chaiscript retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss)); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -131,7 +131,7 @@ namespace chaiscript return t_ss.get_object(this->text); } catch (std::exception &) { - throw Eval_Error("Can not find object: " + this->text); + throw exception::eval_error("Can not find object: " + this->text); } } } @@ -171,7 +171,7 @@ namespace chaiscript try { plb << this->children[1]->children[i]->eval(t_ss); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]->children[i]); throw; } @@ -192,9 +192,9 @@ namespace chaiscript } catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { t_ss.set_stack(prev_stack); return rv.retval; } @@ -203,10 +203,10 @@ namespace chaiscript throw; } } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.set_stack(prev_stack); - throw Eval_Error(ee.reason); + throw exception::eval_error(ee.reason); } } @@ -226,7 +226,7 @@ namespace chaiscript try { plb << this->children[1]->children[i]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]->children[i]); throw; } @@ -240,18 +240,18 @@ namespace chaiscript return (*boxed_cast(fn))(plb); } catch(const exception::dispatch_error &e){ - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + 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) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - throw Eval_Error(ee.reason); + throw exception::eval_error(ee.reason); } } @@ -282,7 +282,7 @@ namespace chaiscript try { retval = this->children.back()->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()); throw; } @@ -303,14 +303,14 @@ namespace chaiscript retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); } catch(const exception::dispatch_error &){ - throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); + throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); } } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not clone right hand side of equation"); + throw exception::eval_error("Can not clone right hand side of equation"); } } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -322,10 +322,10 @@ namespace chaiscript lhs.assign(retval); } else { - throw Eval_Error("Mismatched types in equation"); + throw exception::eval_error("Mismatched types in equation"); } } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -335,9 +335,9 @@ namespace chaiscript retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i+1]->text + "'"); + throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -358,7 +358,7 @@ namespace chaiscript t_ss.add_object(this->children[0]->text, Boxed_Value()); } catch (const exception::reserved_word_error &) { - throw Eval_Error("Reserved word used as variable '" + this->children[0]->text + "'"); + throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); } return t_ss.get_object(this->children[0]->text); } @@ -397,7 +397,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -407,12 +407,12 @@ namespace chaiscript retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); } catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception"); + throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); + throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -432,7 +432,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -447,7 +447,7 @@ namespace chaiscript try { plb << this->children[i]->children[1]->children[j]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]->children[1]->children[j]); throw; } @@ -472,9 +472,9 @@ namespace chaiscript } catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what())); + throw exception::eval_error(std::string(e.what())); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { t_ss.set_stack(prev_stack); retval = rv.retval; } @@ -488,12 +488,12 @@ namespace chaiscript 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"); + throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); + throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]->children[j]); throw; } @@ -576,11 +576,11 @@ namespace chaiscript return retval; } } - catch (const chaiscript::Return_Value &) { + catch (const chaiscript::detail::Return_Value &) { t_ss.pop_scope(); throw; } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); t_ss.pop_scope(); throw; @@ -644,7 +644,7 @@ namespace chaiscript l_annotation, guard)), l_function_name); } catch (const exception::reserved_word_error &e) { - throw Eval_Error("Reserved word used as function name '" + e.word() + "'"); + throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); } return Boxed_Value(); } @@ -666,9 +666,9 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); + throw exception::eval_error("While condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -678,7 +678,7 @@ namespace chaiscript try { this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -688,15 +688,15 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); + throw exception::eval_error("While condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; } } - catch (Break_Loop &) { + catch (detail::Break_Loop &) { cond = false; } } @@ -717,9 +717,9 @@ namespace chaiscript cond = boxed_cast(this->children[0]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("If condition not boolean"); + throw exception::eval_error("If condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -728,7 +728,7 @@ namespace chaiscript try { return this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -741,7 +741,7 @@ namespace chaiscript try { return this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -751,9 +751,9 @@ namespace chaiscript cond = boxed_cast(this->children[i+1]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("'else if' condition not boolean"); + throw exception::eval_error("'else if' condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -761,7 +761,7 @@ namespace chaiscript try { return this->children[i+2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+2]); throw; } @@ -792,7 +792,7 @@ namespace chaiscript try { this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -800,7 +800,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[1]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -809,7 +809,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -818,7 +818,7 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); + throw exception::eval_error("For condition not boolean"); } while (cond) { try { @@ -826,7 +826,7 @@ namespace chaiscript try { this->children[3]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[3]); throw; } @@ -834,7 +834,7 @@ namespace chaiscript try { this->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[2]); throw; } @@ -842,7 +842,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[1]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -851,7 +851,7 @@ namespace chaiscript try { this->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[2]); throw; } @@ -859,7 +859,7 @@ namespace chaiscript try { this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -867,7 +867,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -876,9 +876,9 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); + throw exception::eval_error("For condition not boolean"); } - catch (Break_Loop &) { + catch (detail::Break_Loop &) { cond = false; } } @@ -900,7 +900,7 @@ namespace chaiscript try { vec.push_back(this->children[0]->children[i]->eval(t_ss)); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[i]); throw; } @@ -925,7 +925,7 @@ namespace chaiscript 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) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[i]); throw; } @@ -933,7 +933,7 @@ namespace chaiscript return const_var(retval); } catch (const exception::dispatch_error &) { - throw Eval_Error("Can not find appropriate 'Map()'"); + throw exception::eval_error("Can not find appropriate 'Map()'"); } } @@ -947,15 +947,15 @@ namespace chaiscript virtual Boxed_Value eval(Dispatch_Engine &t_ss){ if (this->children.size() > 0) { try { - throw Return_Value(this->children[0]->eval(t_ss)); + throw detail::Return_Value(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } } else { - throw Return_Value(Boxed_Value()); + throw detail::Return_Value(Boxed_Value()); } } @@ -975,7 +975,7 @@ namespace chaiscript return retval; } } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -994,7 +994,7 @@ namespace chaiscript 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 + "'"); + throw exception::eval_error("Can not find appropriate unary '" + this->children[0]->text + "'"); } } @@ -1006,7 +1006,7 @@ namespace chaiscript 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(); + throw detail::Break_Loop(); } }; @@ -1036,9 +1036,9 @@ namespace chaiscript this->children[0]->children[0]->children[1]->eval(t_ss)); } catch (const exception::dispatch_error &) { - throw Eval_Error("Unable to generate range vector"); + throw exception::eval_error("Unable to generate range vector"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[0]); throw; } @@ -1065,13 +1065,13 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::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) { + catch (exception::eval_error &ee2) { ee2.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1096,7 +1096,7 @@ namespace chaiscript try { retval = catch_block->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[0]); throw; } @@ -1108,7 +1108,7 @@ namespace chaiscript try { retval = catch_block->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1127,20 +1127,20 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::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"); + throw exception::eval_error("Guard condition not boolean"); } if (guard) { try { retval = catch_block->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[2]); throw; } @@ -1153,14 +1153,14 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::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"); + throw exception::eval_error("Internal error: catch block size unrecognized"); } } } @@ -1174,7 +1174,7 @@ namespace chaiscript try { retval = catch_block->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[0]); throw; } @@ -1187,7 +1187,7 @@ namespace chaiscript try { retval = catch_block->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1207,7 +1207,7 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1215,9 +1215,9 @@ namespace chaiscript } t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); + throw exception::eval_error("Guard condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1225,7 +1225,7 @@ namespace chaiscript try { retval = catch_block->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[2]); throw; } @@ -1237,14 +1237,14 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::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"); + throw exception::eval_error("Internal error: catch block size unrecognized"); } } } @@ -1253,7 +1253,7 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1267,7 +1267,7 @@ namespace chaiscript try { retval = this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1365,7 +1365,7 @@ namespace chaiscript } } catch (const exception::reserved_word_error &e) { - throw Eval_Error("Reserved word used as method name '" + e.word() + "'"); + throw exception::eval_error("Reserved word used as method name '" + e.word() + "'"); } return Boxed_Value(); } @@ -1384,7 +1384,7 @@ namespace chaiscript } catch (const exception::reserved_word_error &) { - throw Eval_Error("Reserved word used as attribute '" + this->children[1]->text + "'"); + throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'"); } return Boxed_Value(); } @@ -1436,7 +1436,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -1448,13 +1448,13 @@ namespace chaiscript lhs = boxed_cast(retval); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); + throw exception::eval_error("Condition not boolean"); } if (lhs) { try { retval = this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -1479,7 +1479,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -1491,7 +1491,7 @@ namespace chaiscript lhs = boxed_cast(retval); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); + throw exception::eval_error("Condition not boolean"); } if (lhs) { retval = Boxed_Value(true); @@ -1500,7 +1500,7 @@ namespace chaiscript try { retval = this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index de8b3933..1a574d69 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -16,566 +16,275 @@ namespace chaiscript { - namespace detail + namespace parser { - enum Alphabet - { symbol_alphabet = 0 + namespace detail + { + 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[detail::max_alphabet][detail::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("//") - { - setup_operators(); + , 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 < detail::lengthof_alphabet ; ++c ) { - for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) { - m_alphabet[a][c]=false; - } - } - 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; - - 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(); - } - } - - /** - * 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,detail::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,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 { - --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; - } + 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, 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; - } + /** + * 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, 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; - } - } - 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 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; - } - } - } - - /** - * 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 { @@ -583,1392 +292,1686 @@ namespace chaiscript ++m_input_pos; } } - } while (Symbol("#")); - - std::string match(start, m_input_pos); - 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; + retval = true; + } + return retval; } - else { - return false; + + /** + * 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; + } + else if (SkipComment()) { + retval = true; + } + else { + break; + } + } + return retval; } - } - /** - * 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; + /** + * 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 (has_more_input()) { - ++m_input_pos; + 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 exception::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 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 { - throw Eval_Error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); + 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; + } } } - 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 { + /** + * 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 (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(); + if (Symbol_("#")) { + do { + while (m_input_pos != m_input_end) { + if (Eol_()) { + break; + } + else { + ++m_col; + ++m_input_pos; + } + } + } while (Symbol("#")); - //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; + std::string match(start, m_input_pos); + 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; + } + else { + return false; + } + } - while (s != end) { - if (saw_interpolation_marker) { - if (*s == '{') { - //We've found an interpolation point + /** + * 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; + } + ++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); + } + } + 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 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 = ""; - 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); + std::string eval_match; - 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; + 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(); + 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); + 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(); + 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); + 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(); + 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); + 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::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::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::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::Fun_Call_AST_Node()), tostr_stack_top); - build_match(AST_NodePtr(new eval::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); + 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 if (*s == '$') { - saw_interpolation_marker = true; + 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 { - match.push_back(*s); + 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; } - is_escaped = false; + ++s; } - ++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); + 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); + 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); + 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 { - 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 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 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 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 (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) ) { + 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 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 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,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 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 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 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 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 eval::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 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 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 eval::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 eval::Finally_AST_Node()), finally_stack_top); - } - build_match(AST_NodePtr(new eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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")) { + m_match_stack.back()->text = "else if"; + 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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 eval::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 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 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 eval::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 eval::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 eval::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 eval::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/src/main.cpp b/src/main.cpp index dbffe039..53ea64e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,14 +107,14 @@ void interactive(chaiscript::ChaiScript& chai) 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; } @@ -205,7 +205,7 @@ 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 << ")"; diff --git a/src/reflection.cpp b/src/reflection.cpp index d5fc6cb6..f858863d 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -71,8 +71,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect ); CHAISCRIPT_CLASS( m, - chaiscript::ChaiScript_Parser, - (chaiscript::ChaiScript_Parser ()), + chaiscript::parser::ChaiScript_Parser, + (chaiscript::parser::ChaiScript_Parser ()), ((parse)) ((ast)) ); From deb4cb036f203bc42cc2664487aabf8a2a4f3e74 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 24 Mar 2011 09:26:41 -0600 Subject: [PATCH 04/13] Hide Bare_Type in detail namespace --- include/chaiscript/dispatchkit/type_info.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 001bf9a7..733d926e 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -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 From 58e5df0a9a83a6b5fce2d1618d0d5c69cf777699 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 25 Mar 2011 15:42:18 -0600 Subject: [PATCH 05/13] Even more reorganization of namespaces to help with documentation and clarity. --- include/chaiscript/dispatchkit/bootstrap.hpp | 68 +- .../dispatchkit/boxed_pod_value.hpp | 318 ++-- .../chaiscript/dispatchkit/dispatchkit.hpp | 1286 +++++++++-------- .../chaiscript/dispatchkit/dynamic_object.hpp | 449 +++--- .../chaiscript/dispatchkit/function_call.hpp | 94 +- .../dispatchkit/function_call_detail.hpp | 123 +- .../dispatchkit/proxy_constructors.hpp | 49 +- .../dispatchkit/proxy_functions.hpp | 927 ++++++------ .../dispatchkit/register_function.hpp | 70 +- .../chaiscript/language/chaiscript_common.hpp | 2 +- .../chaiscript/language/chaiscript_engine.hpp | 20 +- .../chaiscript/language/chaiscript_eval.hpp | 102 +- samples/example.cpp | 8 +- src/main.cpp | 2 +- src/reflection.cpp | 6 +- unittests/dynamic_object_test.cpp | 2 +- 16 files changed, 1777 insertions(+), 1749 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 29d1b3bd..e970210e 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -31,7 +31,7 @@ namespace chaiscript P1 &assign_pod(P1 &p1, Boxed_POD_Value v) { - if (v.m_isfloat) + if (v.isfloat) { return (p1 = P1(v.d)); } else { @@ -42,7 +42,7 @@ namespace chaiscript template P1 construct_pod(Boxed_POD_Value v) { - if (v.m_isfloat) + if (v.isfloat) { return P1(v.d); } else { @@ -53,7 +53,7 @@ namespace chaiscript template P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 &= P1(r.i); } @@ -64,7 +64,7 @@ namespace chaiscript template P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 ^= P1(r.i); } @@ -75,7 +75,7 @@ namespace chaiscript template P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 |= P1(r.i); } @@ -86,7 +86,7 @@ namespace chaiscript template P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 -= P1(r.d); } else { @@ -97,7 +97,7 @@ namespace chaiscript template P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 <<= P1(r.i); } @@ -109,7 +109,7 @@ namespace chaiscript template P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 *= P1(r.d); } else { @@ -120,7 +120,7 @@ namespace chaiscript template P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 /= P1(r.d); } else { @@ -131,7 +131,7 @@ namespace chaiscript template P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 %= P1(r.i); } @@ -143,7 +143,7 @@ namespace chaiscript template P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r) { - if (!r.m_isfloat) + if (!r.isfloat) { return p1 >>= P1(r.i); } @@ -155,7 +155,7 @@ namespace chaiscript template P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r) { - if (r.m_isfloat) + if (r.isfloat) { return p1 += P1(r.d); } else { @@ -458,7 +458,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 +480,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 +491,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 +509,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 +535,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,7 +552,7 @@ 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); } @@ -570,14 +570,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 +587,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 +648,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/boxed_pod_value.hpp b/include/chaiscript/dispatchkit/boxed_pod_value.hpp index 42d7faeb..57b52669 100644 --- a/include/chaiscript/dispatchkit/boxed_pod_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_pod_value.hpp @@ -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/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 9467b584..591238aa 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -111,151 +111,153 @@ 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 detail::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(); - } - }; - + }; + } namespace exception { @@ -300,396 +302,398 @@ namespace chaiscript }; } - /** - * 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(); + } + +#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.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 exception::global_non_const(); + 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; + } + + 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? + { #ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_global_object_mutex); + boost::shared_lock l(m_global_object_mutex); #endif - m_state.m_global_objects[name] = obj; - } + std::map::const_iterator itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + return itr->second; + } + } - /** - * Adds a new scope to the stack - */ - void new_scope() - { - StackData &stack = get_stack_data(); - stack.push_back(Scope()); - } + // If all that failed, then check to see if it's a function + std::vector funcs = get_function(name); - /** - * 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"); - } - } - - /** - * 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; - } - - 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()) + if (funcs.empty()) { - return stackitr->second; + 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) { + add_global_const(const_var(ti), name + "_type"); + #ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_global_object_mutex); + boost::unique_lock l(m_mutex); #endif - std::map::const_iterator itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) + 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; } + + 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) +#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 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 - { + /** + * Return all registered types + */ + std::vector > get_types() const + { #ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); + 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) - { - if (itr->second.bare_equal(ti)) + 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; +#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()) + { + return itr->second; + } else { + return std::vector(); + } + } + + /** + * 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(); + 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(); - } - - } - - /** - * Return true if a function exists - */ - bool function_exists(const std::string &name) const - { #ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); + boost::shared_lock l(m_mutex); #endif + std::vector > rets; - const std::map > &functions = get_functions_int(); - return functions.find(name) != functions.end(); - } + const std::map > &functions = get_functions_int(); - /** - * 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) - { + void add_reserved_word(const std::string &name) + { #ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); + 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 detail::dispatch(functions.begin(), functions.end(), params); - } + return dispatch::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(); @@ -717,9 +721,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; @@ -746,249 +750,249 @@ 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()); } - - - for (int i = 1; i < lhssize && i < rhssize; ++i) + State get_state() { - 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; - } - - - /** - * 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); + boost::unique_lock l(m_mutex); + boost::unique_lock l2(m_global_object_mutex); #endif - if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) - { - throw exception::reserved_word_error(name); + return m_state; } - } - /** - * 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) - { + void set_state(const State &t_state) + { #ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); + boost::unique_lock l(m_mutex); + boost::unique_lock l2(m_global_object_mutex); #endif - std::map > &funcs = get_functions_int(); - - std::map >::iterator itr - = funcs.find(t_name); + m_state = t_state; + } - if (itr != funcs.end()) + + private: + /** + * Returns the current stack + * make const/non const versions + */ + StackData &get_stack_data() const { - std::vector &vec = itr->second; - for (std::vector::const_iterator itr2 = vec.begin(); - itr2 != vec.end(); - ++itr2) + 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) { - 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; - } + /** + * Throw a reserved_word exception if the name is not allowed + */ + void validate_object_name(const std::string &name) const + { #ifndef CHAISCRIPT_NO_THREADS - mutable boost::shared_mutex m_mutex; - mutable boost::shared_mutex m_global_object_mutex; + boost::shared_lock l(m_mutex); #endif - struct Stack_Holder - { - Stack_Holder() - : stack(new StackData()) - { - stack->push_back(Scope()); + 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) + { +#ifndef CHAISCRIPT_NO_THREADS + boost::unique_lock l(m_mutex); +#endif - 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; + } + +#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()) + { + 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_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 732bd8a3..02690888 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -11,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..434d3db1 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -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 d6798c84..49a877ae 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -23,35 +23,38 @@ namespace chaiscript { - namespace detail + namespace dispatch { + namespace detail + { - /** - * 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) + /** + * Internal helper class for handling the return + * value of a build_function_caller + */ + template + struct Function_Caller_Ret { - return boxed_cast(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) + /** + * Specialization for void return types + */ + template<> + struct Function_Caller_Ret { - dispatch(t_funcs, params); - } - }; + static void call(const std::vector &t_funcs, + const std::vector ¶ms) + { + dispatch::dispatch(t_funcs, params); + } + }; + } } } @@ -65,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/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index ed3a7c9c..73e0afe2 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -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 4ec0bc9f..97ef808b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -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()) - || detail::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,382 +195,385 @@ 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: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; + 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; - }; + + 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; + }; + } namespace exception { @@ -587,15 +593,16 @@ namespace chaiscript 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 detail + 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 @@ -635,7 +642,7 @@ namespace chaiscript Boxed_Value dispatch(const Funcs &funcs, const std::vector &plist) { - return dispatch(funcs.begin(), funcs.end(), plist); + return dispatch::dispatch(funcs.begin(), funcs.end(), plist); } } } diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index fbd4fc29..8db81134 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -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/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index f2730e3b..7196ef16 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -99,7 +99,7 @@ namespace chaiscript return to_string(); } - virtual Boxed_Value eval(Dispatch_Engine &) { + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) { Boxed_Value bv; throw std::runtime_error("Undispatched ast_node (internal error)"); } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index af7ca14f..b495048c 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -235,7 +235,7 @@ namespace chaiscript std::vector m_modulepaths; std::vector m_usepaths; - Dispatch_Engine m_engine; + chaiscript::detail::Dispatch_Engine m_engine; /** @@ -307,7 +307,7 @@ namespace chaiscript /** * Returns the current evaluation m_engine */ - Dispatch_Engine &get_eval_engine() { + chaiscript::detail::Dispatch_Engine &get_eval_engine() { return m_engine; } @@ -335,13 +335,13 @@ namespace chaiscript 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(&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(&Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); + 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&); @@ -392,7 +392,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; }; @@ -532,7 +532,7 @@ namespace chaiscript template boost::function functor(const std::string &t_script) { - return chaiscript::functor(eval(t_script)); + return chaiscript::dispatch::functor(eval(t_script)); } /** diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 2718c238..23fa43b7 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -49,7 +49,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { @@ -91,7 +91,7 @@ namespace chaiscript 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 &){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ return const_var(int(atoi(this->text.c_str()))); } @@ -102,7 +102,7 @@ namespace chaiscript 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 &){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ return const_var(double(atof(this->text.c_str()))); } @@ -113,7 +113,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ if (this->text == "true") { return const_var(true); } @@ -163,8 +163,8 @@ namespace chaiscript 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; + virtual Boxed_Value eval(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) { @@ -178,8 +178,8 @@ namespace chaiscript } } - Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - Dispatch_Engine::Stack new_stack = t_ss.new_stack(); + 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); @@ -218,8 +218,8 @@ namespace chaiscript 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; + virtual Boxed_Value eval(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) { @@ -277,7 +277,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { retval = this->children.back()->eval(t_ss); @@ -353,7 +353,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ try { t_ss.add_object(this->children[0]->text, Boxed_Value()); } @@ -391,7 +391,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { @@ -427,7 +427,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { retval = this->children[0]->eval(t_ss); @@ -439,7 +439,7 @@ namespace chaiscript if (this->children.size() > 1) { for (size_t i = 2; i < this->children.size(); i+=2) { - Param_List_Builder plb; + dispatch::Param_List_Builder plb; plb << retval; if (this->children[i]->children.size() > 1) { @@ -462,8 +462,8 @@ namespace chaiscript fun_name = this->children[i]->text; } - Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - Dispatch_Engine::Stack new_stack = t_ss.new_stack(); + 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); @@ -512,7 +512,7 @@ namespace chaiscript 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 &){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ return const_var(this->text); } @@ -523,7 +523,7 @@ namespace chaiscript 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 &){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ return const_var(char(this->text[0])); } @@ -534,7 +534,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; size_t numparams = 0; @@ -550,8 +550,8 @@ namespace chaiscript 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), + 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()))); } @@ -562,7 +562,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ size_t num_children = this->children.size(); t_ss.new_scope(); @@ -602,7 +602,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; size_t numparams = 0; AST_NodePtr guardnode; @@ -626,10 +626,10 @@ namespace chaiscript } } - boost::shared_ptr guard; + boost::shared_ptr guard; if (guardnode) { - guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, + 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)); } @@ -638,7 +638,7 @@ namespace chaiscript 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, + (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); @@ -656,7 +656,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ bool cond; t_ss.new_scope(); @@ -711,7 +711,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ bool cond; try { cond = boxed_cast(this->children[0]->eval(t_ss)); @@ -782,7 +782,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ bool cond; t_ss.new_scope(); @@ -893,7 +893,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(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) { @@ -917,7 +917,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ try { std::map retval; for (size_t i = 0; i < this->children[0]->children.size(); ++i) { @@ -944,7 +944,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ if (this->children.size() > 0) { try { throw detail::Return_Value(this->children[0]->eval(t_ss)); @@ -966,7 +966,7 @@ namespace chaiscript 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) { + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) { const size_t size = this->children.size(); for (size_t i = 0; i < size; ++i) { try { @@ -989,7 +989,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ try { return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss)); } @@ -1005,7 +1005,7 @@ namespace chaiscript 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 &){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ throw detail::Break_Loop(); } }; @@ -1029,7 +1029,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ try { return t_ss.call_function("generate_range", this->children[0]->children[0]->children[0]->eval(t_ss), @@ -1058,7 +1058,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; t_ss.new_scope(); @@ -1300,7 +1300,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; AST_NodePtr guardnode; @@ -1327,10 +1327,10 @@ namespace chaiscript size_t numparams = t_param_names.size(); - boost::shared_ptr guard; + boost::shared_ptr guard; if (guardnode) { - guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, + 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)); } @@ -1341,8 +1341,8 @@ namespace chaiscript 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, + (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); @@ -1356,8 +1356,8 @@ namespace chaiscript // 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, + (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); @@ -1377,9 +1377,9 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ try { - t_ss.add(fun(boost::function(boost::bind(&detail::Dynamic_Object_Attribute::func, this->children[0]->text, + 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); } @@ -1431,7 +1431,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { retval = this->children[0]->eval(t_ss); @@ -1473,7 +1473,7 @@ namespace chaiscript 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){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; try { diff --git a/samples/example.cpp b/samples/example.cpp index e8029822..68aa6c60 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); } @@ -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 53ea64e2..dff7cd93 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,7 @@ void version(int){ bool throws_exception(const chaiscript::Proxy_Function &f) { try { - chaiscript::functor(f)(); + chaiscript::dispatch::functor(f)(); } catch (...) { return true; } diff --git a/src/reflection.cpp b/src/reflection.cpp index f858863d..aca21d9f 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()) 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"); From 92c836c58acdc45bb46418343397a13a3f74ba8f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 25 Mar 2011 22:49:17 -0600 Subject: [PATCH 06/13] Simplify mutex code by providing stubs that are do nothing during CHAISCRIPT_NO_THREADS builds. --- include/chaiscript/chaiscript.hpp | 29 +++++--- include/chaiscript/chaiscript_threading.hpp | 40 +++++++++++ .../chaiscript/dispatchkit/bootstrap_stl.hpp | 11 +-- .../chaiscript/dispatchkit/dispatchkit.hpp | 67 ++++++------------- .../dispatchkit/dynamic_cast_conversion.hpp | 31 +++------ .../chaiscript/language/chaiscript_engine.hpp | 31 +++------ 6 files changed, 106 insertions(+), 103 deletions(-) diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 10576ce3..da1e4e5d 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -7,15 +7,28 @@ #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 ff3689f5..bfc7d6c9 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -13,6 +13,14 @@ #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 @@ -21,6 +29,12 @@ namespace chaiscript { #ifndef CHAISCRIPT_NO_THREADS + using boost::unique_lock; + using boost::shared_lock; + using boost::lock_guard; + using boost::shared_mutex; + using boost::recursive_mutex; + template class Thread_Storage @@ -51,6 +65,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/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 5aed07f4..96710c09 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -5,10 +5,13 @@ // 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/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 591238aa..94d22f0f 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -395,9 +395,7 @@ namespace chaiscript throw exception::global_non_const(); } -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_global_object_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_global_object_mutex); m_state.m_global_objects[name] = obj; } @@ -476,9 +474,7 @@ namespace chaiscript // Is the value we are looking for a global? { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_global_object_mutex); -#endif + 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()) @@ -512,9 +508,7 @@ namespace chaiscript { add_global_const(const_var(ti), name + "_type"); -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); m_state.m_types.insert(std::make_pair(name, ti)); } @@ -524,9 +518,7 @@ namespace chaiscript */ Type_Info get_type(const std::string &name) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); Type_Name_Map::const_iterator itr = m_state.m_types.find(name); @@ -545,9 +537,7 @@ namespace chaiscript */ std::string get_type_name(const Type_Info &ti) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + 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(); @@ -567,9 +557,7 @@ namespace chaiscript */ std::vector > get_types() const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); } @@ -580,9 +568,7 @@ namespace chaiscript std::vector< Proxy_Function > get_function(const std::string &t_name) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); const std::map > &funs = get_functions_int(); @@ -603,9 +589,7 @@ namespace chaiscript */ bool function_exists(const std::string &name) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); const std::map > &functions = get_functions_int(); return functions.find(name) != functions.end(); @@ -616,9 +600,8 @@ namespace chaiscript */ std::vector > get_functions() const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); + std::vector > rets; const std::map > &functions = get_functions_int(); @@ -640,9 +623,7 @@ namespace chaiscript void add_reserved_word(const std::string &name) { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); m_state.m_reserved_words.insert(name); } @@ -779,20 +760,16 @@ namespace chaiscript State get_state() { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); - boost::unique_lock l2(m_global_object_mutex); -#endif + 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) { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); - boost::unique_lock l2(m_global_object_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l2(m_global_object_mutex); m_state = t_state; } @@ -918,9 +895,7 @@ namespace chaiscript */ void validate_object_name(const std::string &name) const { -#ifndef CHAISCRIPT_NO_THREADS - boost::shared_lock l(m_mutex); -#endif + chaiscript::detail::threading::shared_lock l(m_mutex); if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) { @@ -935,9 +910,7 @@ namespace chaiscript */ bool add_function(const Proxy_Function &t_f, const std::string &t_name) { -#ifndef CHAISCRIPT_NO_THREADS - boost::unique_lock l(m_mutex); -#endif + chaiscript::detail::threading::unique_lock l(m_mutex); std::map > &funcs = get_functions_int(); @@ -968,10 +941,8 @@ namespace chaiscript return true; } -#ifndef CHAISCRIPT_NO_THREADS - mutable boost::shared_mutex m_mutex; - mutable boost::shared_mutex m_global_object_mutex; -#endif + mutable chaiscript::detail::threading::shared_mutex m_mutex; + mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; struct Stack_Holder { diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 15ef49e3..30f7d891 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -15,10 +15,6 @@ #include #include -#ifndef CHAISCRIPT_NO_THREADS -#include -#endif - namespace chaiscript { namespace exception @@ -156,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) { @@ -173,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); @@ -211,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(); @@ -225,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; }; } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index b495048c..093df7bb 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -223,10 +223,9 @@ namespace chaiscript } 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; @@ -280,17 +279,13 @@ 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 exception::file_not_found_error &) { @@ -403,10 +398,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; @@ -420,10 +413,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; @@ -505,9 +496,7 @@ 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) { From 87c29ebc91dc82ab6354549f0a953820b513f111 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 26 Mar 2011 09:03:36 -0600 Subject: [PATCH 07/13] Ensure that non-shared_ptr, non-boxed_value, non-reference return types are treated as const. --- include/chaiscript/chaiscript_threading.hpp | 1 + .../chaiscript/dispatchkit/handle_return.hpp | 23 ++++++++++++++++++- unittests/assign_const.chai | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 unittests/assign_const.chai diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index bfc7d6c9..85cba1da 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -23,6 +23,7 @@ namespace chaiscript { + /// \internal namespace detail { namespace threading diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index ba2b381a..a79e5b05 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -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/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 } ); From bbe89e61bcad0a6b7f3dbde0780964919e0292e9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 26 Mar 2011 22:42:11 -0600 Subject: [PATCH 08/13] elimination of unused / outdated code and documentation cleanups. --- Doxyfile.in | 2 +- include/chaiscript/chaiscript_threading.hpp | 8 +- .../chaiscript/dispatchkit/bad_boxed_cast.hpp | 14 ++- include/chaiscript/dispatchkit/bind_first.hpp | 27 ++++- include/chaiscript/dispatchkit/bootstrap.hpp | 114 +++++++++++++----- .../chaiscript/language/chaiscript_engine.hpp | 13 -- samples/example.cpp | 4 +- src/main.cpp | 6 +- unittests/functor_creation_test.cpp | 6 +- 9 files changed, 131 insertions(+), 63 deletions(-) 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_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 85cba1da..10d9df23 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -23,20 +23,24 @@ namespace chaiscript { - /// \internal 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::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 { diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 22f6e6a8..ef26d0b3 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -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 9a8a95df..ae468f1a 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -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 e970210e..529ca023 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -21,16 +21,14 @@ 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.isfloat) { return (p1 = P1(v.d)); @@ -39,6 +37,9 @@ 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) { @@ -50,6 +51,10 @@ 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) { @@ -61,6 +66,10 @@ 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) { @@ -72,6 +81,10 @@ 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) { @@ -83,6 +96,10 @@ 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) { @@ -94,6 +111,10 @@ 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) { @@ -106,6 +127,10 @@ 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) { @@ -117,6 +142,10 @@ 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) { @@ -128,6 +157,10 @@ 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) { @@ -140,6 +173,10 @@ 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) { @@ -151,7 +188,10 @@ 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) { @@ -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<< @@ -558,9 +610,9 @@ namespace chaiscript } 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"); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 093df7bb..66575e27 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -511,19 +511,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::dispatch::functor(eval(t_script)); - } - /** * Evaluate a string via eval method */ diff --git a/samples/example.cpp b/samples/example.cpp index 68aa6c60..51ef10aa 100644 --- a/samples/example.cpp +++ b/samples/example.cpp @@ -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)); diff --git a/src/main.cpp b/src/main.cpp index dff7cd93..67581b0a 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::dispatch::functor(f)(); + f(); } catch (...) { return true; } @@ -102,7 +102,7 @@ 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 { - std::cout << chai.functor("to_string")(val) << std::endl; + std::cout << chai.eval >("to_string")(val) << std::endl; } catch (...) {} //If we can't, do nothing } diff --git a/unittests/functor_creation_test.cpp b/unittests/functor_creation_test.cpp index 432ea551..6578a6d5 100644 --- a/unittests/functor_creation_test.cpp +++ b/unittests/functor_creation_test.cpp @@ -7,15 +7,15 @@ int main() chai.eval("def func() { print(\"Hello World\"); } "); - boost::function f = chai.functor("func"); + boost::function f = chai.eval >("func"); f(); - if (chai.functor("to_string")(6) != "6") + if (chai.eval >("to_string")(6) != "6") { return EXIT_FAILURE; } - if (chai.functor("to_string")(chaiscript::var(6)) == "6") + if (chai.eval >("to_string")(chaiscript::var(6)) == "6") { return EXIT_SUCCESS; } else { From d6b8e323733f8ba02e0c62f4f2b74077c2fe1475 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2011 08:17:04 -0600 Subject: [PATCH 09/13] Allow for parse time evaluation of const values. The goal is to allow for more evaluation at parse time, in general, to increase eval time performance. - Make AST_Node non-constructable except by derived classes. - Make data in AST_Node const (as much as possible). - Replace reflection "text = " with replace_child() (where the replacement must be with a new parse tree). - Evaluate floats, strings, ints, chars at parse time to avoid repeat evaluations (~10% speed up in loops in -O3) --- .../chaiscript/language/chaiscript_common.hpp | 83 ++++++++++--------- .../chaiscript/language/chaiscript_eval.hpp | 36 +++++--- .../chaiscript/language/chaiscript_parser.hpp | 7 +- src/reflection.cpp | 3 +- unittests/reflection_test.chai | 6 +- 5 files changed, 84 insertions(+), 51 deletions(-) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 7196ef16..8eee1325 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -61,48 +61,57 @@ namespace chaiscript * 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; + 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(chaiscript::detail::Dispatch_Engine &) + { + Boxed_Value bv; + throw std::runtime_error("Undispatched ast_node (internal error)"); + } + + 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(chaiscript::detail::Dispatch_Engine &) { - Boxed_Value bv; - throw std::runtime_error("Undispatched ast_node (internal error)"); - } }; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 23fa43b7..d918016c 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -89,23 +89,30 @@ namespace chaiscript 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) { } + 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(chaiscript::detail::Dispatch_Engine &){ - return const_var(int(atoi(this->text.c_str()))); + 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) { } + 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(chaiscript::detail::Dispatch_Engine &){ - return const_var(double(atof(this->text.c_str()))); + return m_value; } + private: + Boxed_Value m_value; + }; struct Id_AST_Node : public AST_Node { @@ -472,7 +479,7 @@ namespace chaiscript } catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw exception::eval_error(std::string(e.what())); + throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name); } catch(detail::Return_Value &rv) { t_ss.set_stack(prev_stack); @@ -510,23 +517,30 @@ namespace chaiscript 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) { } + 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(chaiscript::detail::Dispatch_Engine &){ - return const_var(this->text); + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) { + return m_value; } + private: + Boxed_Value m_value; + }; 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) { } + 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(chaiscript::detail::Dispatch_Engine &){ - return const_var(char(this->text[0])); + return m_value; } + private: + Boxed_Value m_value; }; struct Lambda_AST_Node : public AST_Node { @@ -656,7 +670,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) { bool cond; t_ss.new_scope(); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 1a574d69..985cf221 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1312,7 +1312,12 @@ namespace chaiscript has_matches = false; if (Keyword("else", true)) { if (Keyword("if")) { - m_match_stack.back()->text = "else 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); } diff --git a/src/reflection.cpp b/src/reflection.cpp index aca21d9f..ee8d152c 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -62,7 +62,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)) @@ -70,6 +70,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect ((end)) ((internal_to_string)) ((children)) + ((replace_child)) ); CHAISCRIPT_CLASS( m, 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") From de5822873b9831361256441df7d62b9f605d1541 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2011 10:03:37 -0600 Subject: [PATCH 10/13] Use RAII for scope management Possibly fixes a few bugs where scope pops where missed. --- .../chaiscript/language/chaiscript_common.hpp | 21 +++++- .../chaiscript/language/chaiscript_eval.hpp | 66 ++++--------------- 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 8eee1325..176c5992 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -90,7 +90,6 @@ namespace chaiscript virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) { - Boxed_Value bv; throw std::runtime_error("Undispatched ast_node (internal error)"); } @@ -175,6 +174,26 @@ namespace chaiscript struct Break_Loop { Break_Loop() { } }; + + /// 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(); + } + + ~Scope_Push_Pop() + { + m_de.pop_scope(); + } + + + private: + chaiscript::detail::Dispatch_Engine &m_de; + }; + } } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index d918016c..729fa9db 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -18,27 +18,20 @@ 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; + return t_node->eval(t_ss); } catch (const detail::Return_Value &rv) { - t_ss.pop_scope(); return rv.retval; } catch (exception::eval_error &ee) { ee.call_stack.push_back(t_node); - t_ss.pop_scope(); throw; - } catch (...) { - t_ss.pop_scope(); - throw; - } + } } @@ -89,7 +82,8 @@ namespace chaiscript 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())))) { } + 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(chaiscript::detail::Dispatch_Engine &){ return m_value; @@ -577,35 +571,28 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - size_t num_children = this->children.size(); + const size_t num_children = this->children.size(); + + detail::Scope_Push_Pop spp(t_ss); - 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::detail::Return_Value &) { - t_ss.pop_scope(); throw; } catch (exception::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(); } @@ -673,18 +660,16 @@ namespace chaiscript virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) { bool cond; - t_ss.new_scope(); + detail::Scope_Push_Pop spp(t_ss); try { cond = boxed_cast(this->children[0]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); throw exception::eval_error("While condition not boolean"); } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); throw; } while (cond) { @@ -701,12 +686,10 @@ namespace chaiscript cond = boxed_cast(this->children[0]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); throw exception::eval_error("While condition not boolean"); } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); throw; } } @@ -714,10 +697,9 @@ namespace chaiscript cond = false; } } - t_ss.pop_scope(); return Boxed_Value(); } - ; + }; struct If_AST_Node : public AST_Node { @@ -799,7 +781,7 @@ namespace chaiscript virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ bool cond; - t_ss.new_scope(); + detail::Scope_Push_Pop spp(t_ss); try { if (this->children.size() == 4) { @@ -825,13 +807,11 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); throw; } } } catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); throw exception::eval_error("For condition not boolean"); } while (cond) { @@ -883,20 +863,17 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - t_ss.pop_scope(); throw; } } } catch (const exception::bad_boxed_cast &) { - t_ss.pop_scope(); throw exception::eval_error("For condition not boolean"); } catch (detail::Break_Loop &) { cond = false; } } - t_ss.pop_scope(); return Boxed_Value(); } @@ -1075,7 +1052,8 @@ namespace chaiscript virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; - t_ss.new_scope(); + detail::Scope_Push_Pop spp(t_ss); + try { retval = this->children[0]->eval(t_ss); } @@ -1087,11 +1065,9 @@ namespace chaiscript } catch (exception::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) { @@ -1143,11 +1119,9 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); throw exception::eval_error("Guard condition not boolean"); } if (guard) { @@ -1169,17 +1143,14 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); throw exception::eval_error("Internal error: catch block size unrecognized"); } } } - catch (Boxed_Value &bv) { - Boxed_Value except = bv; + catch (Boxed_Value &except) { for (size_t i = 1; i < this->children.size(); ++i) { AST_NodePtr catch_block = this->children[i]; @@ -1223,12 +1194,10 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); throw exception::eval_error("Guard condition not boolean"); } catch (exception::eval_error &ee) { @@ -1253,11 +1222,9 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); throw exception::eval_error("Internal error: catch block size unrecognized"); } } @@ -1269,11 +1236,9 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); throw; } @@ -1283,13 +1248,10 @@ namespace chaiscript } catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); - t_ss.pop_scope(); throw; } } - t_ss.pop_scope(); - return retval; } From 79e8af4f6ed5c697355d8ac5bb13db572b63a950 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2011 21:03:24 -0600 Subject: [PATCH 11/13] Enhance eval error stack reporting Use OOP to avoid code duplication for eval error tracking. This results in much more robust stack error reporting and 400 LOC less. --- .../chaiscript/language/chaiscript_common.hpp | 130 +++-- .../chaiscript/language/chaiscript_eval.hpp | 548 ++++-------------- src/main.cpp | 22 +- src/reflection.cpp | 7 + unittests/eval_error.chai | 39 ++ unittests/unit_test.inc | 18 + 6 files changed, 260 insertions(+), 504 deletions(-) create mode 100644 unittests/eval_error.chai diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 176c5992..124b0528 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -8,6 +8,7 @@ #define CHAISCRIPT_COMMON_HPP_ #include +#include namespace chaiscript { @@ -57,65 +58,6 @@ namespace chaiscript typedef boost::shared_ptr AST_NodePtr; - /** - * The struct that doubles as both a parser ast_node and an AST node - */ - struct AST_Node { - public: - const std::string text; - const int identifier; - boost::shared_ptr filename; - File_Position start, end; - std::vector children; - AST_NodePtr annotation; - - /** - * 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 + " "); - } - return oss.str(); - } - - std::string internal_to_string() { - return to_string(); - } - - virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) - { - throw std::runtime_error("Undispatched ast_node (internal error)"); - } - - 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() {} - - }; - - - - namespace exception { /** @@ -157,6 +99,76 @@ namespace chaiscript } + /** + * The struct that doubles as both a parser ast_node and an AST node + */ + 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; + + /** + * 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 + " "); + } + return oss.str(); + } + + std::string internal_to_string() { + return to_string(); + } + + 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)"); + } + }; + + + + + namespace detail { /** diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 729fa9db..35132d49 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -28,9 +28,6 @@ namespace chaiscript return t_node->eval(t_ss); } catch (const detail::Return_Value &rv) { return rv.retval; - } catch (exception::eval_error &ee) { - ee.call_stack.push_back(t_node); - throw; } } @@ -42,16 +39,10 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + retval = this->children[0]->eval(t_ss); for (size_t i = 1; i < this->children.size(); i += 2) { try { @@ -60,10 +51,6 @@ namespace chaiscript catch(const exception::dispatch_error &){ throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'"); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } } return retval; @@ -85,7 +72,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ return m_value; } @@ -100,7 +87,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ return m_value; } @@ -114,7 +101,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ if (this->text == "true") { return const_var(true); } @@ -164,18 +151,12 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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) { - try { - plb << this->children[1]->children[i]->eval(t_ss); - } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); - throw; - } + plb << this->children[1]->children[i]->eval(t_ss); } } @@ -205,9 +186,8 @@ namespace chaiscript } } catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); t_ss.set_stack(prev_stack); - throw exception::eval_error(ee.reason); + throw; } } @@ -219,42 +199,29 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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) { - try { - plb << this->children[1]->children[i]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]->children[i]); - throw; - } + plb << this->children[1]->children[i]->eval(t_ss); } } + Boxed_Value fn = this->children[0]->eval(t_ss); + try { - Boxed_Value fn = this->children[0]->eval(t_ss); - - try { - return (*boxed_cast(fn))(plb); - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); - } - catch(detail::Return_Value &rv) { - return rv.retval; - } - catch(...) { - throw; - } + return (*boxed_cast(fn))(plb); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw exception::eval_error(ee.reason); + catch(const exception::dispatch_error &e){ + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } + catch(detail::Return_Value &rv) { + return rv.retval; + } + catch(...) { + throw; } - } }; @@ -278,70 +245,45 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children.back()->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()); - throw; - } + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + Boxed_Value retval = this->children.back()->eval(t_ss); 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 { - Boxed_Value lhs = this->children[i]->eval(t_ss); + if (lhs.is_undef()) { + retval = t_ss.call_function("clone", retval); + retval.clear_dependencies(); + } try { - if (lhs.is_undef()) { - retval = t_ss.call_function("clone", retval); - retval.clear_dependencies(); - } - - try { - retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); - } - catch(const exception::dispatch_error &){ - throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); - } + retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); } catch(const exception::dispatch_error &){ - throw exception::eval_error("Can not clone right hand side of equation"); + throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); } } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not clone right hand side of equation"); } } else if (this->children[i+1]->text == ":=") { - try { - Boxed_Value lhs = this->children[i]->eval(t_ss); - if (lhs.is_undef() || type_match(lhs, retval)) { - lhs.assign(retval); - } - else { - throw exception::eval_error("Mismatched types in equation"); - } - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; + Boxed_Value lhs = this->children[i]->eval(t_ss); + if (lhs.is_undef() || type_match(lhs, retval)) { + lhs.assign(retval); + } else { + throw exception::eval_error("Mismatched types in equation"); } } else { try { retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); - } - catch(const exception::dispatch_error &){ + } catch(const exception::dispatch_error &){ throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'"); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } } } } @@ -354,7 +296,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ try { t_ss.add_object(this->children[0]->text, Boxed_Value()); } @@ -392,16 +334,8 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - Boxed_Value retval; - - try { - retval = this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + 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 { @@ -413,10 +347,6 @@ namespace chaiscript catch(const exception::dispatch_error &){ throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } } return retval; @@ -428,15 +358,8 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + 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) { @@ -445,13 +368,7 @@ namespace chaiscript if (this->children[i]->children.size() > 1) { for (size_t j = 0; j < this->children[i]->children[1]->children.size(); ++j) { - try { - plb << this->children[i]->children[1]->children[j]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]->children[1]->children[j]); - throw; - } + plb << this->children[i]->children[1]->children[j]->eval(t_ss); } } @@ -494,10 +411,6 @@ namespace chaiscript catch(const exception::dispatch_error &){ throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]->children[j]); - throw; - } } } } @@ -514,7 +427,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &) { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) { return m_value; } @@ -529,7 +442,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ return m_value; } @@ -542,7 +455,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; size_t numparams = 0; @@ -570,7 +483,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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); @@ -587,10 +500,6 @@ namespace chaiscript catch (const chaiscript::detail::Return_Value &) { throw; } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; - } } return Boxed_Value(); @@ -603,7 +512,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; size_t numparams = 0; AST_NodePtr guardnode; @@ -657,7 +566,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss) { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { bool cond; detail::Scope_Push_Pop spp(t_ss); @@ -668,19 +577,9 @@ namespace chaiscript catch (const exception::bad_boxed_cast &) { throw exception::eval_error("While condition not boolean"); } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } while (cond) { try { - try { - this->children[1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } + this->children[1]->eval(t_ss); try { cond = boxed_cast(this->children[0]->eval(t_ss)); @@ -688,10 +587,6 @@ namespace chaiscript catch (const exception::bad_boxed_cast &) { throw exception::eval_error("While condition not boolean"); } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } } catch (detail::Break_Loop &) { cond = false; @@ -707,7 +602,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ bool cond; try { cond = boxed_cast(this->children[0]->eval(t_ss)); @@ -715,32 +610,16 @@ namespace chaiscript catch (const exception::bad_boxed_cast &) { throw exception::eval_error("If condition not boolean"); } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } if (cond) { - try { - return this->children[1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } + 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") { - try { - return this->children[i+1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } + return this->children[i+1]->eval(t_ss); } else if (this->children[i]->text == "else if") { try { @@ -749,18 +628,8 @@ namespace chaiscript catch (const exception::bad_boxed_cast &) { throw exception::eval_error("'else if' condition not boolean"); } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } if (cond) { - try { - return this->children[i+2]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+2]); - throw; - } + return this->children[i+2]->eval(t_ss); } } i = i + 3; @@ -778,37 +647,18 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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) { - try { - this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + this->children[0]->eval(t_ss); - try { - cond = boxed_cast(this->children[1]->eval(t_ss)); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } - } - else { - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + 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 &) { @@ -817,54 +667,17 @@ namespace chaiscript while (cond) { try { if (this->children.size() == 4) { - try { - this->children[3]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[3]); - throw; - } + this->children[3]->eval(t_ss); + this->children[2]->eval(t_ss); - try { - this->children[2]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[2]); - throw; - } - - try { - cond = boxed_cast(this->children[1]->eval(t_ss)); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } + cond = boxed_cast(this->children[1]->eval(t_ss)); } else { - try { - this->children[2]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[2]); - throw; - } + this->children[2]->eval(t_ss); - try { - this->children[1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[1]); - throw; - } + this->children[1]->eval(t_ss); - try { - cond = boxed_cast(this->children[0]->eval(t_ss)); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + cond = boxed_cast(this->children[0]->eval(t_ss)); } } catch (const exception::bad_boxed_cast &) { @@ -884,17 +697,11 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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) { - try { - vec.push_back(this->children[0]->children[i]->eval(t_ss)); - } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]->children[i]); - throw; - } + vec.push_back(this->children[0]->children[i]->eval(t_ss)); } } @@ -908,18 +715,12 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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) { - try { - 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(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]->children[i]); - throw; - } + 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)); } return const_var(retval); } @@ -935,15 +736,9 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ if (this->children.size() > 0) { - try { - throw detail::Return_Value(this->children[0]->eval(t_ss)); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + throw detail::Return_Value(this->children[0]->eval(t_ss)); } else { throw detail::Return_Value(Boxed_Value()); @@ -957,18 +752,12 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss) { + 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) { - try { - const Boxed_Value &retval = this->children[i]->eval(t_ss); - if (i + 1 == size) { - return retval; - } - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i]); - throw; + const Boxed_Value &retval = this->children[i]->eval(t_ss); + if (i + 1 == size) { + return retval; } } return Boxed_Value(); @@ -980,13 +769,8 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - try { - return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss)); - } - catch(std::exception &){ - throw exception::eval_error("Can not find appropriate unary '" + this->children[0]->text + "'"); - } + 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)); } }; @@ -996,7 +780,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ throw detail::Break_Loop(); } }; @@ -1020,7 +804,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ try { return t_ss.call_function("generate_range", this->children[0]->children[0]->children[0]->eval(t_ss), @@ -1029,10 +813,6 @@ namespace chaiscript catch (const exception::dispatch_error &) { throw exception::eval_error("Unable to generate range vector"); } - catch(exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]->children[0]); - throw; - } } }; @@ -1049,7 +829,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; detail::Scope_Push_Pop spp(t_ss); @@ -1058,15 +838,8 @@ namespace chaiscript retval = this->children[0]->eval(t_ss); } catch (exception::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 (exception::eval_error &ee2) { - ee2.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw; } @@ -1083,25 +856,13 @@ namespace chaiscript if (catch_block->children.size() == 1) { //No variable capture, no guards - try { - retval = catch_block->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[0]); - throw; - } + 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); - try { - retval = catch_block->children[1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[1]); - throw; - } + retval = catch_block->children[1]->eval(t_ss); break; } @@ -1114,37 +875,18 @@ namespace chaiscript 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 (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw exception::eval_error("Guard condition not boolean"); } if (guard) { - try { - retval = catch_block->children[2]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[2]); - throw; - } - + retval = catch_block->children[2]->eval(t_ss); break; } } else { if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw exception::eval_error("Internal error: catch block size unrecognized"); } @@ -1156,27 +898,13 @@ namespace chaiscript if (catch_block->children.size() == 1) { //No variable capture, no guards - try { - retval = catch_block->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[0]); - throw; - } - + 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); - try { - retval = catch_block->children[1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[1]); - throw; - } - + retval = catch_block->children[1]->eval(t_ss); break; } else if (catch_block->children.size() == 3) { @@ -1189,41 +917,19 @@ namespace chaiscript } 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 (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw exception::eval_error("Guard condition not boolean"); } - catch (exception::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 (exception::eval_error &ee) { - ee.call_stack.push_back(catch_block->children[2]); - throw; - } + retval = catch_block->children[2]->eval(t_ss); break; } } else { if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw exception::eval_error("Internal error: catch block size unrecognized"); } @@ -1231,25 +937,13 @@ namespace chaiscript } catch (...) { if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - this->children.back()->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + this->children.back()->children[0]->eval(t_ss); } throw; } if (this->children.back()->identifier == AST_Node_Type::Finally) { - try { - retval = this->children.back()->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children.back()->children[0]); - throw; - } + retval = this->children.back()->children[0]->eval(t_ss); } return retval; @@ -1276,7 +970,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ std::vector t_param_names; AST_NodePtr guardnode; @@ -1353,7 +1047,7 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + 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); @@ -1407,15 +1101,8 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ - Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + 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) { @@ -1427,13 +1114,7 @@ namespace chaiscript throw exception::eval_error("Condition not boolean"); } if (lhs) { - try { - retval = this->children[i+1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } + retval = this->children[i+1]->eval(t_ss); } else { retval = Boxed_Value(false); @@ -1449,37 +1130,20 @@ namespace chaiscript 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(chaiscript::detail::Dispatch_Engine &t_ss){ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ Boxed_Value retval; - try { - retval = this->children[0]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[0]); - throw; - } + 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"); - } + bool lhs = boxed_cast(retval); + if (lhs) { retval = Boxed_Value(true); } else { - try { - retval = this->children[i+1]->eval(t_ss); - } - catch (exception::eval_error &ee) { - ee.call_stack.push_back(this->children[i+1]); - throw; - } + retval = this->children[i+1]->eval(t_ss); } } } diff --git a/src/main.cpp b/src/main.cpp index 67581b0a..bc833322 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,6 +63,17 @@ bool throws_exception(const boost::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() ) { @@ -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 ) { @@ -209,9 +221,13 @@ int main(int argc, char *argv[]) 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 ee8d152c..98f0dbb0 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -52,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()) 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/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)) From 8ecd3a084b500a798e881ccbac15a756798bea22 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 28 Mar 2011 19:50:41 -0600 Subject: [PATCH 12/13] Add simple efficencies for static ids --- .../chaiscript/language/chaiscript_eval.hpp | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 35132d49..b7609a7c 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -99,22 +99,16 @@ namespace chaiscript 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) { } + 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 (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 { + 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); } @@ -123,6 +117,27 @@ namespace chaiscript } } } + + 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 { @@ -168,7 +183,7 @@ namespace chaiscript try { t_ss.set_stack(new_stack); - const Boxed_Value &retval = (*boxed_cast(fn))(plb); + const Boxed_Value &retval = (*boxed_cast(fn))(plb); t_ss.set_stack(prev_stack); return retval; } @@ -208,10 +223,8 @@ namespace chaiscript } } - 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 exception::dispatch_error &e){ throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); From a91c66d286afbdeaa5ec213bea468b0688826985 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 29 Mar 2011 09:28:35 -0600 Subject: [PATCH 13/13] Couple of include guard cleanups --- include/chaiscript/dispatchkit/function_call.hpp | 4 ++-- include/chaiscript/utility/utility.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 434d3db1..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 diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 7409acba..27489302 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -4,8 +4,8 @@ // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com -#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP__ -#define CHAISCRIPT_UTILITY_UTILITY_HPP__ +#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ +#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #include "../chaiscript.hpp" #include