Compare commits

..

43 Commits

Author SHA1 Message Date
Jason Turner
59df213e66 Update version to 4.2.0 2012-11-30 20:38:17 -07:00
Jason Turner
0ea8931b21 Add ability to call functions requiring arithmetic value conversions
- Conversions are only attempted on a dispatch
 - Conversions are only attempted after a normal dispatch has failed
 - Conversions are only attempted if exactly one function matches
   the signature of the parameters passed in - excluding the mismatched
   arithmetic parameters
 - This feature should not be relied on in performance critical code
   overhead is added for each function call that requires a conversion
   to execute, see the tests performed above.
2012-11-27 21:21:37 -07:00
Jason Turner
f24d376fa5 Update for release 4.1.1 2012-11-17 20:48:25 -07:00
Jason Turner
7917ea02dc Fix linux build error discovered with 4.0.0 release 2012-11-17 20:30:53 -07:00
Jason Turner
deef33640c Update releasenotes and version numbers for 4.1.0 release 2012-11-17 18:31:48 -07:00
Jason Turner
58f3256389 Fix function pointer issue for substr on VS 2010 32bit 2012-11-16 13:58:03 -07:00
Jason Turner
f1a4c4c427 Fix compiler warning found on VS 2008 64bit 2012-11-16 12:57:15 -07:00
Jason Turner
afd27a4b01 Fix errors and warnings found on VisualStudio 2005 2012-11-16 12:27:41 -07:00
Jason Turner
4c65e45598 Correct signing and sizing of integer literals #77 2012-11-10 16:31:05 -07:00
Jason Turner
923369a4f4 Add support for string::substr #75
Also add forgotten missing test for number suffixes
2012-11-07 15:48:25 -07:00
Jason Turner
964342bff3 Prevent leaking macros #76 2012-11-07 14:13:08 -07:00
Jason Turner
623c64299a Add ability to specify number prefixes for floating point and integers. 2012-11-07 12:05:34 -07:00
Jason Turner
9832d1ce39 Add insert and insert_ref methods to "map" types 2012-09-26 12:38:32 -06:00
Jason Turner
ed7bdfb172 Add "erase" function to associative sets (maps) 2012-09-26 11:31:19 -06:00
Jason Turner
204ab53afc Update readme.txt to readme.md for better formatting. 2012-08-14 12:00:44 -06:00
Jason Turner
8f7226051e Add boost::system to linkage to support boost 1.50. Should not cause any issue for older users of boost 2012-08-14 08:59:48 -06:00
Jason Turner
46d1c50923 Merge pull request #66 from mgee/master
Make Boxed_Number utility functions const
2012-07-18 06:29:22 -07:00
Markus Groß
9e3c2960aa Make some Boxed_Number functions const. 2012-07-17 18:26:58 +02:00
Jason Turner
9fd4a1b9f5 Merge pull request #53 from mgee/master
More Boxed_Number enhancements
2012-07-16 21:18:18 -07:00
Jason Turner
441cdf0935 Add test showing c linkage working fine [#16] 2012-07-16 22:10:40 -06:00
Jason Turner
f0016d978a Add test to make sure simultaneous ChaiScript instantiations work 2012-07-16 21:51:06 -06:00
Jason Turner
1155720b14 Add the ability to save and restore the state of local variables #25 2012-07-16 21:27:42 -06:00
Jason Turner
f5b7be3743 Correct building on threadless 2012-07-13 13:14:48 -06:00
Jason Turner
d8f881239f Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2012-07-13 12:36:37 -06:00
Jason Turner
0a436398dd Use make_shared #64 2012-07-13 12:25:50 -06:00
Jason Turner
9f309fcbe9 Add tests for multithreaded features #55 2012-07-10 15:10:09 -06:00
Jason Turner
4e33e969dc Minor header file include cleanup 2012-07-10 13:27:47 -06:00
Markus Groß
08d9d9e28e Adapt toString to proper naming scheme. 2012-07-03 18:42:27 +02:00
Markus Groß
935276fccd Adapt getAs function to proper naming scheme. 2012-07-03 18:42:04 +02:00
Markus Groß
f8feaf6ea8 Add toString function to Boxed_Number.
For uint8_t, int8_t and char the value is first
converted to an appropriate int type.
This way the value is converted to a number
rather than a character.
2012-06-29 16:48:53 +02:00
Markus Groß
dfcc415c31 Add getAs<T> function to Boxed_Number to enable casting to a target type. 2012-06-29 08:00:00 +02:00
Markus Groß
927235d871 Add templated constructor to Boxed_Number to allow creating from primitive number types. 2012-06-29 07:42:16 +02:00
Jason Turner
bf4f90a4ff Fix build error for building without threads 2012-06-25 16:44:22 -06:00
Jason Turner
45f07f9924 Update method error output to show the expression it is trying to execute. 2012-06-25 16:26:36 -06:00
Jason Turner
39d817469c Optionally allow the user to specify the file name to report to end users when calling "eval" 2012-06-25 08:05:58 -06:00
Jason Turner
7a25625fdd Fix failing error reporting for solitary (non-dispatched) guarded function 2012-06-25 07:53:15 -06:00
Jason Turner
5e6a51ba63 Add failing unit test for remaining error condition to check for. 2012-06-25 07:44:14 -06:00
Jason Turner
a8ea5f151d Extreme error reporting capabilities update and bug fixes 2012-06-25 06:31:34 -06:00
Jason Turner
5a76d98692 Enhance and correct error messages
Backported from C++11 branch.

Conflicts:

	include/chaiscript/dispatchkit/proxy_functions.hpp
	include/chaiscript/language/chaiscript_common.hpp
	include/chaiscript/language/chaiscript_eval.hpp
	include/chaiscript/language/chaiscript_parser.hpp
2012-06-22 18:00:10 -06:00
Jason Turner
3bccf4d977 Explicitly link to pthreads, seems some systems need this #47 2012-06-09 18:02:35 -04:00
Jason Turner
d2aba2ef56 Eliminate boost::lexical_cast usage completely #39 2012-06-03 09:20:15 -06:00
Jason Turner
832df7f9e8 Remove offending boost code which causes warnings in some cases #39 2012-06-02 17:45:10 -06:00
Jason Turner
6c53e08e9b Fix compiler warning in snow leopard 2012-06-01 15:07:53 -06:00
35 changed files with 1881 additions and 260 deletions

View File

@@ -13,11 +13,11 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES ".swp")
list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~") list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.txt") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 4) set(CPACK_PACKAGE_VERSION_MAJOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_MINOR 2)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -79,26 +79,31 @@ set (Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscri
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
if (MULTITHREAD_SUPPORT_ENABLED) if (MULTITHREAD_SUPPORT_ENABLED)
find_package(Boost 1.36.0 COMPONENTS thread) find_package(Boost 1.36.0 COMPONENTS thread system)
if (Boost_FOUND) if (Boost_FOUND)
link_directories( ${Boost_LIBRARY_DIRS} ) link_directories( ${Boost_LIBRARY_DIRS} )
else() else()
message(FATAL_ERROR "Can not find Boost") message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND) endif(Boost_FOUND)
if (CMAKE_HOST_UNIX)
add_definitions(-pthread)
list(APPEND LIBS "pthread")
endif()
else() else()
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if (CMAKE_HOST_UNIX) if (CMAKE_HOST_UNIX)
set(DYNAMIC_LOADER "dl") list(APPEND LIBS "dl")
endif(CMAKE_HOST_UNIX) endif(CMAKE_HOST_UNIX)
list(APPEND LIBS ${READLINE_LIB})
if (MSVC) if (NOT MSVC)
# Boost on MSVC does automatic linking # Boost on MSVC does automatic linking
set(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB}) list(APPEND LIBS ${Boost_LIBRARIES})
else()
set(LIBS ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
endif() endif()
if (CMAKE_COMPILER_2005) if (CMAKE_COMPILER_2005)
@@ -187,6 +192,42 @@ if(BUILD_TESTING)
target_link_libraries(short_comparison_test ${LIBS}) target_link_libraries(short_comparison_test ${LIBS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test) add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS})
add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS})
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS})
add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
set_property(TEST Multithreaded_Test
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
unittests/multifile_test_module.cpp) unittests/multifile_test_module.cpp)

View File

@@ -140,7 +140,10 @@
/// ///
/// \subsubsection addingobjects Adding Objects /// \subsubsection addingobjects Adding Objects
/// ///
/// Named objects can be created with the chaiscript::var function. /// Named objects can be created with the chaiscript::var function. Note: adding a object
/// adds it to the current thread scope, not to a global scope. If you have multiple
/// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself.
/// ///
/// \code /// \code
/// using namespace chaiscript; /// using namespace chaiscript;

View File

@@ -89,5 +89,6 @@ namespace chaiscript
#undef n #undef n
#undef m #undef m
#undef param
#endif #endif

View File

@@ -13,6 +13,7 @@
#include "operators.hpp" #include "operators.hpp"
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include <boost/function_types/result_type.hpp> #include <boost/function_types/result_type.hpp>
#include <sstream>
namespace chaiscript namespace chaiscript
{ {
@@ -93,27 +94,34 @@ namespace chaiscript
/** /**
* to_string function for internal use. Uses ostream operator<< * to_string function for internal use. Uses ostream operator<<
*/ */
template<typename Input> template<typename Input>
std::string to_string(Input i) std::string to_string(Input i)
{ {
return boost::lexical_cast<std::string>(i); std::stringstream ss;
} ss << i;
return ss.str();
}
/** /**
* Internal function for converting from a string to a value * Internal function for converting from a string to a value
* uses ostream operator >> to perform the conversion * uses ostream operator >> to perform the conversion
*/ */
template<typename Input> template<typename Input>
Input parse_string(const std::string &i) Input parse_string(const std::string &i)
{ {
return boost::lexical_cast<Input>(i); std::stringstream ss(i);
} Input t;
ss >> t;
return t;
}
/** /**
* Add all common functions for a POD type. All operators, and * Add all common functions for a POD type. All operators, and
* common conversions * common conversions
@@ -419,6 +427,7 @@ namespace chaiscript
m->add(fun(&Type_Info::is_void), "is_type_void"); m->add(fun(&Type_Info::is_void), "is_type_void");
m->add(fun(&Type_Info::is_undef), "is_type_undef"); m->add(fun(&Type_Info::is_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer"); m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m->add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m->add(fun(&Type_Info::bare_equal), "bare_equal"); m->add(fun(&Type_Info::bare_equal), "bare_equal");
@@ -438,6 +447,7 @@ namespace chaiscript
bootstrap_pod_type<long double>("long_double", m); bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m); bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m); bootstrap_pod_type<int>("int", m);
bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m); bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m); bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<size_t>("size_t", m); bootstrap_pod_type<size_t>("size_t", m);

View File

@@ -176,6 +176,19 @@ namespace chaiscript
return t_func(t_obj, p1); return t_func(t_obj, p1);
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif
}
template<typename T, typename P1>
int return_int_impl_non_const(const boost::function<typename T::size_type (T *, P1)> &t_func, T *t_obj, P1 p1)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif #endif
} }
@@ -185,6 +198,13 @@ namespace chaiscript
return boost::bind(&return_int_impl<T, P1>, boost::function<size_t (const T *, P1)>(boost::mem_fn(t_func)), _1, _2); return boost::bind(&return_int_impl<T, P1>, boost::function<size_t (const T *, P1)>(boost::mem_fn(t_func)), _1, _2);
} }
template<typename T, typename P1>
boost::function<int (T *, P1)> return_int(size_t (T::*t_func)(P1) )
{
return boost::bind(&return_int_impl_non_const<T, P1>, boost::function<size_t (T*, P1)>(boost::mem_fn(t_func)), _1, _2);
}
template<typename T, typename P1, typename P2> template<typename T, typename P1, typename P2>
int return_int_impl(const boost::function<typename T::size_type (const T *, P1, P2)> &t_func, const T *t_obj, P1 p1, P2 p2) int return_int_impl(const boost::function<typename T::size_type (const T *, P1, P2)> &t_func, const T *t_obj, P1 p1, P2 p2)
{ {
@@ -198,12 +218,32 @@ namespace chaiscript
#endif #endif
} }
template<typename StringType, StringType (StringType::*Func)(typename StringType::size_type, typename StringType::size_type) const >
StringType substr_helper(const StringType &str, int begin, int end)
{
return (str.*Func)(begin, end);
}
template<typename T, typename P1, typename P2> template<typename T, typename P1, typename P2>
boost::function<int (const T *, P1, P2)> return_int(size_t (T::*t_func)(P1, P2) const) boost::function<int (const T *, P1, P2)> return_int(size_t (T::*t_func)(P1, P2) const)
{ {
return boost::bind(&return_int_impl<T, P1, P2>, boost::function<size_t (const T *, P1, P2)>(boost::mem_fn(t_func)), _1, _2, _3); return boost::bind(&return_int_impl<T, P1, P2>, boost::function<size_t (const T *, P1, P2)>(boost::mem_fn(t_func)), _1, _2, _3);
} }
template<typename T>
void insert(T &t_target, const T &t_other)
{
t_target.insert(t_other.begin(), t_other.end());
}
template<typename T>
void insert_ref(T &t_target, const typename T::value_type &t_val)
{
t_target.insert(t_val);
}
/** /**
* Add Bidir_Range support for the given ContainerType * Add Bidir_Range support for the given ContainerType
@@ -452,6 +492,23 @@ namespace chaiscript
{ {
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(&ContainerType::count))), "count"); m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(&ContainerType::count))), "count");
typedef size_t (ContainerType::*erase)(const typename ContainerType::key_type &);
erase eraseptr(&ContainerType::erase);
m->add(fun(boost::function<int (ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(eraseptr))), "erase");
m->add(fun(&detail::insert<ContainerType>), "insert");
std::string insert_name;
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref";
} else {
insert_name = "insert";
}
m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
return m; return m;
} }
@@ -581,6 +638,8 @@ namespace chaiscript
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
m->add(fun(&detail::substr_helper<String, &String::substr>), "substr");
m->add(fun(&String::c_str), "c_str"); m->add(fun(&String::c_str), "c_str");
m->add(fun(&String::data), "data"); m->add(fun(&String::data), "data");

View File

@@ -4,8 +4,8 @@
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef __boxed_cast_hpp__ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define __boxed_cast_hpp__ #define CHAISCRIPT_BOXED_CAST_HPP_
#include "type_info.hpp" #include "type_info.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"

View File

@@ -298,7 +298,20 @@ namespace chaiscript
throw boost::bad_any_cast(); throw boost::bad_any_cast();
} }
} }
template<typename Target, typename Source>
Target get_as_aux() const
{
return static_cast<Target>(*static_cast<const Source *>(bv.get_const_ptr()));
}
template<typename Source>
std::string to_string_aux(const Boxed_Value &v) const
{
std::ostringstream oss;
oss << *static_cast<const Source *>(v.get_const_ptr());
return oss.str();
}
public: public:
@@ -313,6 +326,133 @@ namespace chaiscript
validate_boxed_number(v); validate_boxed_number(v);
} }
template<typename T> explicit Boxed_Number(T t)
: bv(Boxed_Value(t))
{
validate_boxed_number(bv);
}
Boxed_Number get_as(const Type_Info &inp_) const
{
if (inp_.bare_equal_type_info(typeid(int))) {
return Boxed_Number(get_as<int>());
} else if (inp_.bare_equal_type_info(typeid(double))) {
return Boxed_Number(get_as<double>());
} else if (inp_.bare_equal_type_info(typeid(float))) {
return Boxed_Number(get_as<float>());
} else if (inp_.bare_equal_type_info(typeid(long double))) {
return Boxed_Number(get_as<long double>());
} else if (inp_.bare_equal_type_info(typeid(char))) {
return Boxed_Number(get_as<char>());
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
return Boxed_Number(get_as<unsigned int>());
} else if (inp_.bare_equal_type_info(typeid(long))) {
return Boxed_Number(get_as<long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
return Boxed_Number(get_as<unsigned long>());
} else if (inp_.bare_equal_type_info(typeid(boost::int8_t))) {
return Boxed_Number(get_as<boost::int8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int16_t))) {
return Boxed_Number(get_as<boost::int16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int32_t))) {
return Boxed_Number(get_as<boost::int32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int64_t))) {
return Boxed_Number(get_as<boost::int64_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint8_t))) {
return Boxed_Number(get_as<boost::uint8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint16_t))) {
return Boxed_Number(get_as<boost::uint16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint32_t))) {
return Boxed_Number(get_as<boost::uint32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint64_t))) {
return Boxed_Number(get_as<boost::uint64_t>());
} else {
throw boost::bad_any_cast();
}
}
template<typename Target> Target get_as() const
{
const Type_Info &inp_ = bv.get_type_info();
if (inp_ == typeid(int)) {
return get_as_aux<Target, int>();
} else if (inp_ == typeid(double)) {
return get_as_aux<Target, double>();
} else if (inp_ == typeid(float)) {
return get_as_aux<Target, float>();
} else if (inp_ == typeid(long double)) {
return get_as_aux<Target, long double>();
} else if (inp_ == typeid(char)) {
return get_as_aux<Target, char>();
} else if (inp_ == typeid(unsigned int)) {
return get_as_aux<Target, unsigned int>();
} else if (inp_ == typeid(long)) {
return get_as_aux<Target, long>();
} else if (inp_ == typeid(unsigned long)) {
return get_as_aux<Target, unsigned long>();
} else if (inp_ == typeid(boost::int8_t)) {
return get_as_aux<Target, boost::int8_t>();
} else if (inp_ == typeid(boost::int16_t)) {
return get_as_aux<Target, boost::int16_t>();
} else if (inp_ == typeid(boost::int32_t)) {
return get_as_aux<Target, boost::int32_t>();
} else if (inp_ == typeid(boost::int64_t)) {
return get_as_aux<Target, boost::int64_t>();
} else if (inp_ == typeid(boost::uint8_t)) {
return get_as_aux<Target, boost::uint8_t>();
} else if (inp_ == typeid(boost::uint16_t)) {
return get_as_aux<Target, boost::uint16_t>();
} else if (inp_ == typeid(boost::uint32_t)) {
return get_as_aux<Target, boost::uint32_t>();
} else if (inp_ == typeid(boost::uint64_t)) {
return get_as_aux<Target, boost::uint64_t>();
} else {
throw boost::bad_any_cast();
}
}
std::string to_string() const
{
const Type_Info &inp_ = bv.get_type_info();
if (inp_ == typeid(int)) {
return to_string_aux<int>(bv);
} else if (inp_ == typeid(double)) {
return to_string_aux<double>(bv);
} else if (inp_ == typeid(float)) {
return to_string_aux<float>(bv);
} else if (inp_ == typeid(long double)) {
return to_string_aux<long double>(bv);
} else if (inp_ == typeid(char)) {
return to_string_aux<int>(Boxed_Value(get_as_aux<int, char>()));
} else if (inp_ == typeid(unsigned int)) {
return to_string_aux<unsigned int>(bv);
} else if (inp_ == typeid(long)) {
return to_string_aux<long>(bv);
} else if (inp_ == typeid(unsigned long)) {
return to_string_aux<unsigned long>(bv);
} else if (inp_ == typeid(boost::int8_t)) {
return to_string_aux<int>(Boxed_Value(get_as_aux<int, boost::int8_t>()));
} else if (inp_ == typeid(boost::int16_t)) {
return to_string_aux<boost::int16_t>(bv);
} else if (inp_ == typeid(boost::int32_t)) {
return to_string_aux<boost::int32_t>(bv);
} else if (inp_ == typeid(boost::int64_t)) {
return to_string_aux<boost::int64_t>(bv);
} else if (inp_ == typeid(boost::uint8_t)) {
return to_string_aux<unsigned int>(Boxed_Value(get_as_aux<unsigned int, boost::uint8_t>()));
} else if (inp_ == typeid(boost::uint16_t)) {
return to_string_aux<boost::uint16_t>(bv);
} else if (inp_ == typeid(boost::uint32_t)) {
return to_string_aux<boost::uint32_t>(bv);
} else if (inp_ == typeid(boost::uint64_t)) {
return to_string_aux<boost::uint64_t>(bv);
} else {
throw boost::bad_any_cast();
}
}
bool operator==(const Boxed_Number &t_rhs) const bool operator==(const Boxed_Number &t_rhs) const
{ {

View File

@@ -13,6 +13,7 @@
#include <map> #include <map>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
@@ -77,12 +78,11 @@ namespace chaiscript
{ {
static boost::shared_ptr<Data> get(Boxed_Value::Void_Type) static boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{ {
return boost::shared_ptr<Data> (new Data( return boost::make_shared<Data>(
detail::Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
boost::any(), boost::any(),
false, false,
0) static_cast<void *>(0));
);
} }
template<typename T> template<typename T>
@@ -94,12 +94,11 @@ namespace chaiscript
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj) static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{ {
return boost::shared_ptr<Data>(new Data( return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
false, false,
obj.get()) obj.get());
);
} }
template<typename T> template<typename T>
@@ -111,34 +110,31 @@ namespace chaiscript
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj) static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{ {
return boost::shared_ptr<Data>(new Data( return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
true, true,
obj.get_pointer()) obj.get_pointer());
);
} }
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(const T& t) static boost::shared_ptr<Data> get(const T& t)
{ {
boost::shared_ptr<T> p(new T(t)); boost::shared_ptr<T> p(new T(t));
return boost::shared_ptr<Data>(new Data( return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(p), boost::any(p),
false, false,
p.get()) p.get());
);
} }
static boost::shared_ptr<Data> get() static boost::shared_ptr<Data> get()
{ {
return boost::shared_ptr<Data> (new Data( return boost::make_shared<Data>(
Type_Info(), Type_Info(),
boost::any(), boost::any(),
false, false,
0) static_cast<void *>(0));
);
} }
}; };

View File

@@ -12,8 +12,6 @@
#include <map> #include <map>
#include <set> #include <set>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
@@ -668,6 +666,27 @@ namespace chaiscript
return functions.find(name) != functions.end(); return functions.find(name) != functions.end();
} }
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
return scope;
}
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
scope = t_locals;
}
/// ///
/// Get a map of all objects that can be seen from the current scope in a scripting context /// Get a map of all objects that can be seen from the current scope in a scripting context
@@ -782,10 +801,9 @@ namespace chaiscript
/** /**
* Dump object info to stdout * Dump object info to stdout
*/ */
void dump_object(Boxed_Value o) const void dump_object(const Boxed_Value &o) const
{ {
Type_Info ti = o.get_type_info(); std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl;
std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl;
} }
/** /**
@@ -877,7 +895,7 @@ namespace chaiscript
return false; return false;
} }
std::string type_name(Boxed_Value obj) const std::string type_name(const Boxed_Value &obj) const
{ {
return get_type_name(obj.get_type_info()); return get_type_name(obj.get_type_info());
} }
@@ -1091,6 +1109,14 @@ namespace chaiscript
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec;
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else { } else {
std::vector<Proxy_Function> vec; std::vector<Proxy_Function> vec;
vec.push_back(t_f); vec.push_back(t_f);

View File

@@ -114,6 +114,8 @@ namespace chaiscript
} }
} }
#undef n #undef n
#undef addparam
#undef curry
#endif #endif

View File

@@ -25,7 +25,6 @@ namespace chaiscript
typedef boost::shared_ptr<struct AST_Node> AST_NodePtr; typedef boost::shared_ptr<struct AST_Node> AST_NodePtr;
namespace dispatch namespace dispatch
{ {
/** /**
@@ -86,6 +85,11 @@ namespace chaiscript
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
bool has_arithmetic_param() const
{
return m_has_arithmetic_param;
}
virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
{ {
return std::vector<boost::shared_ptr<const Proxy_Function_Base> >(); return std::vector<boost::shared_ptr<const Proxy_Function_Base> >();
@@ -118,23 +122,8 @@ namespace chaiscript
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
protected: static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv)
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types)
{ {
}
virtual bool compare_first_type(const Boxed_Value &bv) const
{
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef() || (!bv.get_type_info().is_undef()
@@ -151,6 +140,36 @@ namespace chaiscript
return false; return false;
} }
} }
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types), m_has_arithmetic_param(false)
{
for (int i = 1; i < m_types.size(); ++i)
{
if (m_types[i].is_arithmetic())
{
m_has_arithmetic_param = true;
return;
}
}
}
virtual bool compare_first_type(const Boxed_Value &bv) const
{
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
return compare_type_to_param(ti, bv);
}
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
{ {
@@ -171,6 +190,8 @@ namespace chaiscript
} }
std::vector<Type_Info> m_types; std::vector<Type_Info> m_types;
bool m_has_arithmetic_param;
}; };
} }
@@ -591,22 +612,107 @@ namespace chaiscript
class dispatch_error : public std::runtime_error class dispatch_error : public std::runtime_error
{ {
public: public:
dispatch_error() throw() dispatch_error(const std::vector<Boxed_Value> &t_parameters,
: std::runtime_error("No matching function to dispatch to") const std::vector<Const_Proxy_Function> &t_functions)
: std::runtime_error("Error with function dispatch"), parameters(t_parameters), functions(t_functions)
{ {
} }
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() {}
std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions;
}; };
} }
namespace dispatch namespace dispatch
{ {
namespace detail
{
template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist)
{
if (t_func->get_arity() != plist.size())
{
return false;
}
const std::vector<Type_Info> &types = t_func->get_param_types();
assert(plist.size() == types.size() - 1);
for (int i = 0; i < plist.size(); ++i)
{
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i])
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
{
// types continue to match
} else {
return false;
}
}
// all types match
return true;
}
template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist)
{
InItr orig(begin);
InItr matching_func(end);
while (begin != end)
{
if (types_match_except_for_arithmetic(*begin, plist))
{
if (matching_func == end)
{
matching_func = begin;
} else {
// More than one function matches, not attempting
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
++begin;
}
if (matching_func == end)
{
// no appropriate function to attempt arithmetic type conversion on
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
std::vector<Boxed_Value> newplist;
const std::vector<Type_Info> &tis = (*matching_func)->get_param_types();
for (int i = 0; i < plist.size(); ++i)
{
if (tis[i+1].is_arithmetic()
&& plist[i].get_type_info().is_arithmetic()) {
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
} else {
newplist.push_back(plist[i]);
}
}
try {
return (*(*matching_func))(newplist);
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast
} catch (const exception::arity_error &) {
//invalid num params
} catch (const exception::guard_error &) {
//guard failed to allow the function to execute
}
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
/** /**
* Take a vector of functions and a vector of parameters. Attempt to execute * Take a vector of functions and a vector of parameters. Attempt to execute
@@ -614,9 +720,10 @@ namespace chaiscript
* function is found or throw dispatch_error if no matching function is found * function is found or throw dispatch_error if no matching function is found
*/ */
template<typename InItr> template<typename InItr>
Boxed_Value dispatch(InItr begin, InItr end, Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist)
{ {
InItr orig(begin);
while (begin != end) while (begin != end)
{ {
try { try {
@@ -635,7 +742,7 @@ namespace chaiscript
++begin; ++begin;
} }
throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); return detail::dispatch_with_conversions(orig, end, plist);
} }
/** /**

View File

@@ -21,7 +21,6 @@
#include <string> #include <string>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
@@ -121,6 +120,10 @@ namespace chaiscript
} }
#undef n #undef n
#undef gettypeinfo
#undef casthelper
#undef trycast
#endif #endif

View File

@@ -99,6 +99,12 @@ namespace chaiscript
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info); || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
bool bare_equal_type_info(const std::type_info &ti) const
{
return m_bare_type_info != 0
&& (*m_bare_type_info) == ti;
}
bool is_const() const { return m_is_const; } bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; } bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; } bool is_void() const { return m_is_void; }

View File

@@ -69,22 +69,312 @@ namespace chaiscript
File_Position start_position; File_Position start_position;
File_Position end_position; File_Position end_position;
std::string filename; std::string filename;
std::string detail;
std::vector<AST_NodePtr> call_stack; std::vector<AST_NodePtr> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) throw() : eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
std::runtime_error("Error: \"" + t_why + "\" " + const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
(t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + bool t_dot_notation,
+ "at (" + boost::lexical_cast<std::string>(t_where.line) + ", " + const chaiscript::detail::Dispatch_Engine &t_ss) :
boost::lexical_cast<std::string>(t_where.column) + ")"), std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) :
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) :
std::runtime_error(format(t_why, t_where, t_fname)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
{ } {}
eval_error(const std::string &t_why) throw() eval_error(const std::string &t_why) throw()
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why) reason(t_why)
{} {}
std::string pretty_print() const
{
std::ostringstream ss;
ss << what();
if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
ss << std::endl << detail << std::endl;
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << std::endl;
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
}
}
}
ss << std::endl;
return ss.str();
}
virtual ~eval_error() throw() {} virtual ~eval_error() throw() {}
private:
template<typename T>
static int id(const T& t)
{
return t->identifier;
}
template<typename T>
static std::string pretty(const T& t)
{
return t->pretty_print();
}
template<typename T>
static std::string fname(const T& t)
{
return *t->filename;
}
template<typename T>
static std::string startpos(const T& t)
{
std::ostringstream oss;
oss << t->start.line << ", " << t->start.column;
return oss.str();
}
static std::string format_why(const std::string &t_why)
{
return "Error: \"" + t_why + "\"";
}
static std::string format_types(const Const_Proxy_Function &t_func,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types();
std::string retval;
if (arity == -1)
{
retval = "(...)";
if (t_dot_notation)
{
retval = "(Object)." + retval;
}
} else if (types.size() <= 1) {
retval = "()";
} else {
std::stringstream ss;
ss << "(";
std::string paramstr;
for (size_t index = 1;
index != types.size();
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation)
{
paramstr += ").(";
if (types.size() == 2)
{
paramstr += ", ";
}
} else {
paramstr += ", ";
}
}
ss << paramstr.substr(0, paramstr.size() - 2);
ss << ")";
retval = ss.str();
}
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun)
{
Proxy_Function f = dynfun->get_guard();
if (f)
{
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
= boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard)
{
retval += " : " + format_guard(dynfunguard->get_parse_tree());
}
}
retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
}
return retval;
}
template<typename T>
static std::string format_guard(const T &t)
{
return t->pretty_print();
}
template<typename T>
static std::string format_location(const T &t)
{
std::ostringstream oss;
oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
return oss.str();
}
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
if (t_functions.size() == 1)
{
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
} else {
ss << " " << t_functions.size() << " overloads available:" << std::endl;
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
itr != t_functions.end();
++itr)
{
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
}
}
return ss.str();
}
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << "(";
if (!t_parameters.empty())
{
std::string paramstr;
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
itr != t_parameters.end();
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation)
{
paramstr += ").(";
if (t_parameters.size() == 1)
{
paramstr += ", ";
}
} else {
paramstr += ", ";
}
}
ss << paramstr.substr(0, paramstr.size() - 2);
}
ss << ")";
return ss.str();
}
static std::string format_filename(const std::string &t_fname)
{
std::stringstream ss;
if (t_fname != "__EVAL__")
{
ss << "in '" << t_fname << "' ";
} else {
ss << "during evaluation ";
}
return ss.str();
}
static std::string format_location(const File_Position &t_where)
{
std::stringstream ss;
ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str();
}
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
ss << format_filename(t_fname);
ss << " ";
ss << format_location(t_where);
return ss.str();
}
static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
return ss.str();
}
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << format_filename(t_fname);
ss << " ";
ss << format_location(t_where);
return ss.str();
}
}; };
/** /**
@@ -111,6 +401,19 @@ namespace chaiscript
std::vector<AST_NodePtr> children; std::vector<AST_NodePtr> children;
AST_NodePtr annotation; AST_NodePtr annotation;
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
}
return oss.str();
}
/** /**
* Prints the contents of an AST node, including its children, recursively * Prints the contents of an AST node, including its children, recursively
*/ */

View File

@@ -10,7 +10,7 @@
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <chaiscript/language/chaiscript_common.hpp> #include "chaiscript_common.hpp"
#ifdef _POSIX_VERSION #ifdef _POSIX_VERSION
#include <dlfcn.h> #include <dlfcn.h>
@@ -23,8 +23,8 @@
#endif #endif
#include <chaiscript/language/chaiscript_prelude.hpp> #include "chaiscript_prelude.hpp"
#include <chaiscript/language/chaiscript_parser.hpp> #include "chaiscript_parser.hpp"
#include "../dispatchkit/exception_specification.hpp" #include "../dispatchkit/exception_specification.hpp"
namespace chaiscript namespace chaiscript
@@ -456,8 +456,12 @@ namespace chaiscript
std::set<std::string> active_loaded_modules; std::set<std::string> active_loaded_modules;
}; };
/// \brief Returns a state object that represents the current state of the system /// \brief Returns a state object that represents the current state of the global system
/// \return Current state of the system ///
/// The global system includes the reserved words, global const objects, functions and types.
/// local variables are thread specific and not included.
///
/// \return Current state of the global system
/// ///
/// \b Example: /// \b Example:
/// ///
@@ -478,6 +482,10 @@ namespace chaiscript
} }
/// \brief Sets the state of the system /// \brief Sets the state of the system
///
/// The global system includes the reserved words, global objects, functions and types.
/// local variables are thread specific and not included.
///
/// \param[in] t_state New state to set /// \param[in] t_state New state to set
/// ///
/// \b Example: /// \b Example:
@@ -497,7 +505,23 @@ namespace chaiscript
m_engine.set_state(t_state.engine_state); m_engine.set_state(t_state.engine_state);
} }
/// \brief Adds a type, function or object to ChaiScript /// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
return m_engine.get_locals();
}
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
m_engine.set_locals(t_locals);
}
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
/// \param[in] t_t Item to add /// \param[in] t_t Item to add
/// \param[in] t_name Name of item to add /// \param[in] t_name Name of item to add
/// \returns Reference to current ChaiScript object /// \returns Reference to current ChaiScript object
@@ -652,6 +676,8 @@ namespace chaiscript
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
/// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution
/// ///
@@ -659,10 +685,10 @@ namespace chaiscript
/// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type. /// to the requested type.
template<typename T> template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler()) T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
try { try {
return boxed_cast<T>(do_eval(t_input)); return boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv);
@@ -675,14 +701,16 @@ namespace chaiscript
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
/// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution
/// ///
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler()) Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
try { try {
return do_eval(t_input); return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv);

View File

@@ -49,6 +49,16 @@ namespace chaiscript
this->children[2]->eval(t_ss)); this->children[2]->eval(t_ss));
} }
virtual std::string pretty_print() const
{
if (children.size() == 3)
{
return "(" + this->children[0]->pretty_print() + " " + this->children[1]->text + " " + this->children[2]->pretty_print() + ")";
} else {
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
}
}
protected: protected:
Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss, Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss,
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
@@ -74,8 +84,8 @@ namespace chaiscript
return t_ss.call_function(t_oper_string, t_lhs, t_rhs); return t_ss.call_function(t_oper_string, t_lhs, t_rhs);
} }
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "'"); throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
} }
} }
}; };
@@ -93,6 +103,9 @@ namespace chaiscript
Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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(t_ast_node_text.c_str())))) { } m_value(const_var(int(atoi(t_ast_node_text.c_str())))) { }
Int_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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(t_bv) { }
virtual ~Int_AST_Node() {} virtual ~Int_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value; return m_value;
@@ -108,6 +121,9 @@ namespace chaiscript
Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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(t_ast_node_text.c_str())))) { } m_value(const_var(double(atof(t_ast_node_text.c_str())))) { }
Float_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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(t_bv) { }
virtual ~Float_AST_Node() {} virtual ~Float_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value; return m_value;
@@ -181,6 +197,11 @@ namespace chaiscript
Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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) { }
virtual ~Eol_AST_Node() {} virtual ~Eol_AST_Node() {}
virtual std::string pretty_print() const
{
return "\n";
}
}; };
struct Fun_Call_AST_Node : public AST_Node { struct Fun_Call_AST_Node : public AST_Node {
@@ -208,6 +229,23 @@ namespace chaiscript
return retval; return retval;
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
try {
Const_Proxy_Function f = boxed_cast<const Const_Proxy_Function &>(fn);
// handle the case where there is only 1 function to try to call and dispatch fails on it
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(f);
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::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(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
@@ -215,6 +253,24 @@ namespace chaiscript
} }
} }
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
if (j == 0)
{
oss << "(";
}
}
oss << ")";
return oss.str();
}
}; };
struct Inplace_Fun_Call_AST_Node : public AST_Node { struct Inplace_Fun_Call_AST_Node : public AST_Node {
@@ -231,18 +287,53 @@ namespace chaiscript
} }
} }
Boxed_Value bv;
Const_Proxy_Function fn;
try { try {
return (*boxed_cast<const Const_Proxy_Function &>(this->children[0]->eval(t_ss)))(plb); bv = this->children[0]->eval(t_ss);
try {
fn = boxed_cast<const Const_Proxy_Function &>(bv);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
return (*fn)(plb);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
// handle the case where there is only 1 function to try to call and dispatch fails on it
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(fn);
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss);
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::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(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
catch(...) { }
throw;
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
if (j == 0)
{
oss << "(";
}
} }
oss << ")";
return oss.str();
} }
}; };
@@ -252,6 +343,21 @@ namespace chaiscript
Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), 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) { }
virtual ~Arg_List_AST_Node() {} virtual ~Arg_List_AST_Node() {}
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
if (j != 0)
{
oss << ", ";
}
oss << this->children[j]->pretty_print();
}
return oss.str();
}
}; };
struct Variable_AST_Node : public AST_Node { struct Variable_AST_Node : public AST_Node {
@@ -294,12 +400,12 @@ namespace chaiscript
try { try {
retval = t_ss.call_function(this->children[1]->text, lhs, retval); retval = t_ss.call_function(this->children[1]->text, lhs, retval);
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
} }
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not clone right hand side of equation"); throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss);
} }
} }
else if (this->children[1]->text == ":=") { else if (this->children[1]->text == ":=") {
@@ -312,8 +418,8 @@ namespace chaiscript
else { else {
try { try {
retval = t_ss.call_function(this->children[1]->text, lhs, retval); retval = t_ss.call_function(this->children[1]->text, lhs, retval);
} catch(const exception::dispatch_error &){ } catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate '" + this->children[1]->text + "'"); throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
} }
} }
} }
@@ -338,6 +444,11 @@ namespace chaiscript
return t_ss.get_object(this->children[0]->text); return t_ss.get_object(this->children[0]->text);
} }
virtual std::string pretty_print() const
{
return "var " + this->children[0]->text;
}
}; };
struct Comparison_AST_Node : public Binary_Operator_AST_Node { struct Comparison_AST_Node : public Binary_Operator_AST_Node {
@@ -349,7 +460,7 @@ namespace chaiscript
struct Addition_AST_Node : public Binary_Operator_AST_Node { struct Addition_AST_Node : public Binary_Operator_AST_Node {
public: public:
Addition_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Addition, Addition_AST_Node(const std::string &t_ast_node_text = "+", int t_id = AST_Node_Type::Addition,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(),
int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : 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) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
@@ -361,7 +472,7 @@ namespace chaiscript
struct Subtraction_AST_Node : public Binary_Operator_AST_Node { struct Subtraction_AST_Node : public Binary_Operator_AST_Node {
public: public:
Subtraction_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Subtraction, Subtraction_AST_Node(const std::string &t_ast_node_text = "-", int t_id = AST_Node_Type::Subtraction,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 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) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
@@ -373,7 +484,7 @@ namespace chaiscript
struct Multiplication_AST_Node : public Binary_Operator_AST_Node { struct Multiplication_AST_Node : public Binary_Operator_AST_Node {
public: public:
Multiplication_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplication, Multiplication_AST_Node(const std::string &t_ast_node_text = "*", int t_id = AST_Node_Type::Multiplication,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 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) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
@@ -385,7 +496,7 @@ namespace chaiscript
struct Division_AST_Node : public Binary_Operator_AST_Node { struct Division_AST_Node : public Binary_Operator_AST_Node {
public: public:
Division_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Division, Division_AST_Node(const std::string &t_ast_node_text = "/", int t_id = AST_Node_Type::Division,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 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) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
@@ -397,7 +508,7 @@ namespace chaiscript
struct Modulus_AST_Node : public Binary_Operator_AST_Node { struct Modulus_AST_Node : public Binary_Operator_AST_Node {
public: public:
Modulus_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Modulus, Modulus_AST_Node(const std::string &t_ast_node_text = "%", int t_id = AST_Node_Type::Modulus,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 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) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
@@ -431,13 +542,28 @@ namespace chaiscript
catch(std::out_of_range &) { catch(std::out_of_range &) {
throw exception::eval_error("Out of bounds exception"); throw exception::eval_error("Out of bounds exception");
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup '[]' "); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
} }
} }
return retval; return retval;
} }
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << this->children[0]->pretty_print();
for (size_t i = 1; i < this->children.size(); ++i)
{
oss << "[";
oss << this->children[i]->pretty_print();
oss << "]";
}
return oss.str();
}
}; };
struct Dot_Access_AST_Node : public AST_Node { struct Dot_Access_AST_Node : public AST_Node {
@@ -475,7 +601,12 @@ namespace chaiscript
retval = t_ss.call_function(fun_name, plb); retval = t_ss.call_function(fun_name, plb);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name); if (e.functions.empty())
{
throw exception::eval_error("'" + fun_name + "' is not a function.");
} else {
throw exception::eval_error(std::string(e.what()) + " for function '" + fun_name + "'", e.parameters, e.functions, true, t_ss);
}
} }
catch(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
retval = rv.retval; retval = rv.retval;
@@ -489,8 +620,8 @@ namespace chaiscript
catch(std::out_of_range &) { catch(std::out_of_range &) {
throw exception::eval_error("Out of bounds exception"); throw exception::eval_error("Out of bounds exception");
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup '[]' "); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
} }
} }
} }
@@ -512,6 +643,11 @@ namespace chaiscript
return m_value; return m_value;
} }
virtual std::string pretty_print() const
{
return "\"" + text + "\"";
}
private: private:
Boxed_Value m_value; Boxed_Value m_value;
@@ -527,6 +663,11 @@ namespace chaiscript
return m_value; return m_value;
} }
virtual std::string pretty_print() const
{
return "'" + text + "'";
}
private: private:
Boxed_Value m_value; Boxed_Value m_value;
}; };
@@ -908,8 +1049,8 @@ namespace chaiscript
} }
return const_var(retval); return const_var(retval);
} }
catch (const exception::dispatch_error &) { catch (const exception::dispatch_error &e) {
throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for map elements"); throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss);
} }
} }
@@ -971,8 +1112,8 @@ namespace chaiscript
fpp.save_params(params); fpp.save_params(params);
return t_ss.call_function(this->children[0]->text, bv); return t_ss.call_function(this->children[0]->text, bv);
} }
} catch (const exception::dispatch_error &) { } catch (const exception::dispatch_error &e) {
throw exception::eval_error("Error with prefix operator evaluation: " + children[0]->text); throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss);
} }
} }
@@ -1013,8 +1154,8 @@ namespace chaiscript
this->children[0]->children[0]->children[0]->eval(t_ss), this->children[0]->children[0]->children[0]->eval(t_ss),
this->children[0]->children[0]->children[1]->eval(t_ss)); this->children[0]->children[0]->children[1]->eval(t_ss));
} }
catch (const exception::dispatch_error &) { catch (const exception::dispatch_error &e) {
throw exception::eval_error("Unable to generate range vector"); throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss);
} }
} }
@@ -1340,6 +1481,11 @@ namespace chaiscript
} }
return retval; return retval;
} }
virtual std::string pretty_print() const
{
return "(" + AST_Node::pretty_print() + ")";
}
}; };
struct Logical_Or_AST_Node : public AST_Node { struct Logical_Or_AST_Node : public AST_Node {
@@ -1367,6 +1513,11 @@ namespace chaiscript
return retval; return retval;
} }
virtual std::string pretty_print() const
{
return "(" + AST_Node::pretty_print() + ")";
}
}; };
} }

View File

@@ -33,6 +33,8 @@ namespace chaiscript
, bin_alphabet , bin_alphabet
, id_alphabet , id_alphabet
, white_alphabet , white_alphabet
, int_suffix_alphabet
, float_suffix_alphabet
, max_alphabet , max_alphabet
, lengthof_alphabet = 256 , lengthof_alphabet = 256
}; };
@@ -175,6 +177,17 @@ namespace chaiscript
m_alphabet[detail::white_alphabet][static_cast<int>(' ')]=true; m_alphabet[detail::white_alphabet][static_cast<int>(' ')]=true;
m_alphabet[detail::white_alphabet][static_cast<int>('\t')]=true; m_alphabet[detail::white_alphabet][static_cast<int>('\t')]=true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('l')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('L')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('u')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('U')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('l')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('L')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('f')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('F')] = true;
} }
/** /**
@@ -343,6 +356,12 @@ namespace chaiscript
++m_input_pos; ++m_input_pos;
++m_col; ++m_col;
} }
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
} }
else { else {
--m_input_pos; --m_input_pos;
@@ -371,6 +390,11 @@ namespace chaiscript
++m_input_pos; ++m_input_pos;
++m_col; ++m_col;
} }
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
} }
else { else {
--m_input_pos; --m_input_pos;
@@ -386,6 +410,14 @@ namespace chaiscript
return retval; return retval;
} }
void IntSuffix_() {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
}
/** /**
* Reads a binary value from input, without skipping initial whitespace * Reads a binary value from input, without skipping initial whitespace
*/ */
@@ -419,6 +451,173 @@ namespace chaiscript
return retval; return retval;
} }
Boxed_Value buildFloat(const std::string &t_val)
{
bool float_ = false;
bool long_ = false;
size_t i = t_val.size();
for (; i > 0; --i)
{
char val = t_val[i-1];
if (val == 'f' || val == 'F')
{
float_ = true;
} else if (val == 'l' || val == 'L') {
long_ = true;
} else {
break;
}
}
std::stringstream ss(t_val.substr(0, i));
if (float_)
{
float f;
ss >> f;
return Boxed_Value(const_var(f));
} else if (long_) {
long double f;
ss >> f;
return Boxed_Value(const_var(f));
} else {
double f;
ss >> f;
return Boxed_Value(const_var(f));
}
}
template<typename IntType>
Boxed_Value buildInt(const IntType &t_type, const std::string &t_val)
{
bool unsigned_ = false;
bool long_ = false;
bool longlong_ = false;
size_t i = t_val.size();
for (; i > 0; --i)
{
char val = t_val[i-1];
if (val == 'u' || val == 'U')
{
unsigned_ = true;
} else if (val == 'l' || val == 'L') {
if (long_)
{
longlong_ = true;
}
long_ = true;
} else {
break;
}
}
std::stringstream ss(t_val.substr(0, i));
ss >> t_type;
std::stringstream testu(t_val.substr(0, i));
boost::uint64_t u;
testu >> t_type >> u;
bool unsignedrequired = false;
size_t size = sizeof(int) * 8;
if ((u >> (sizeof(int) * 8)) > 0)
{
//requires something bigger than int
long_ = true;
}
BOOST_ASSERT(sizeof(long) == sizeof(boost::uint64_t) || sizeof(long) * 2 == sizeof(boost::uint64_t));
#ifdef BOOST_MSVC
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in this compiler / architecture
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
if ( sizeof(long) < sizeof(boost::uint64_t) && (u >> ((sizeof(boost::uint64_t) - sizeof(long)) * 8)) > 0)
{
//requires something bigger than long
longlong_ = true;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if (longlong_)
{
size = sizeof(boost::int64_t) * 8;
} else if (long_) {
size = sizeof(long) * 8;
}
if ( (u >> (size - 1)) > 0)
{
unsignedrequired = true;
}
if (unsignedrequired && !unsigned_)
{
if (t_type == &std::hex || t_type == &std::oct)
{
// with hex and octal we are happy to just make it unsigned
unsigned_ = true;
} else {
// with decimal we must bump it up to the next size
if (long_)
{
longlong_ = true;
} else if (!long_ && !longlong_) {
long_ = true;
}
}
}
if (unsigned_)
{
if (longlong_)
{
boost::uint64_t val;
ss >> val;
return Boxed_Value(const_var(val));
} else if (long_) {
unsigned long val;
ss >> val;
return Boxed_Value(const_var(val));
} else {
unsigned int val;
ss >> val;
return Boxed_Value(const_var(val));
}
} else {
if (longlong_)
{
boost::int64_t val;
ss >> val;
return Boxed_Value(const_var(val));
} else if (long_) {
long val;
ss >> val;
return Boxed_Value(const_var(val));
} else {
int val;
ss >> val;
return Boxed_Value(const_var(val));
}
}
}
/** /**
* Reads a number from the input, detecting if it's an integer or floating point * Reads a number from the input, detecting if it's an integer or floating point
*/ */
@@ -435,19 +634,14 @@ namespace chaiscript
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) {
if (Hex_()) { if (Hex_()) {
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
std::stringstream ss(match); Boxed_Value i = buildInt(std::hex, match);
unsigned int temp_int; AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
ss >> std::hex >> temp_int;
std::ostringstream out_int;
out_int << static_cast<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); m_match_stack.push_back(t);
return true; return true;
} }
if (Binary_()) { if (Binary_()) {
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
int temp_int = 0; boost::int64_t temp_int = 0;
size_t pos = 0, end = match.length(); size_t pos = 0, end = match.length();
while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { while ((pos < end) && (pos < (2 + sizeof(int) * 8))) {
@@ -458,32 +652,36 @@ namespace chaiscript
++pos; ++pos;
} }
std::ostringstream out_int; Boxed_Value i;
out_int << temp_int; if (match.length() <= sizeof(int) * 8)
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)); {
i = Boxed_Value(const_var(int(temp_int)));
} else {
i = Boxed_Value(const_var(temp_int));
}
AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
return true; return true;
} }
if (Float_()) { if (Float_()) {
std::string match(start, m_input_pos); 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)); Boxed_Value f = buildFloat(match);
AST_NodePtr t(new eval::Float_AST_Node(match, f, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
return true; return true;
} }
else { else {
IntSuffix_();
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
if ((match.size() > 0) && (match[0] == '0')) { if ((match.size() > 0) && (match[0] == '0')) {
std::stringstream ss(match); Boxed_Value i = buildInt(std::oct, match);
unsigned int temp_int; AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
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); m_match_stack.push_back(t);
} }
else { else {
AST_NodePtr t(new eval::Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); Boxed_Value i = buildInt(std::dec, match);
AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
} }
return true; return true;
@@ -1483,10 +1681,10 @@ namespace chaiscript
while (Eol()) {} while (Eol()) {}
while (Case()) { while (Case()) {
while (Eol()); while (Eol()) { } // eat
} }
while (Eol()); while (Eol()) { } // eat
if (!Char('}')) { if (!Char('}')) {
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
@@ -1672,7 +1870,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename);
} }
if (!Char(')')) { if (!Char(')')) {
throw exception::eval_error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename);
} }
} }
return retval; return retval;
@@ -1690,7 +1888,7 @@ namespace chaiscript
retval = true; retval = true;
Container_Arg_List(); Container_Arg_List();
if (!Char(']')) { if (!Char(']')) {
throw exception::eval_error("Missing closing square bracket", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename);
} }
if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { 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) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {

82
readme.md Normal file
View File

@@ -0,0 +1,82 @@
ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details.
Introduction
============
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
native C++ application, it has some advantages over existing embedded scripting
languages:
1) It uses a header-only approach, which makes it easy to integrate with
existing projects.
2) It maintains type safety between your C++ application and the user scripts.
3) It supports a variety of C++ techniques including callbacks, overloaded
functions, class methods, and stl containers.
Requirements
============
ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
Usage
=====
* Add the ChaiScript include directory to your project's header search path
* Add `#include <chaiscript/chaiscript.hpp>` to your source file
* Instantiate the ChaiScript engine in your application. For example, create
a new engine with the name `chai` like so: `chaiscript::ChaiScript chai`
Once instantiated, the engine is ready to start running ChaiScript source. You
have two main options for processing ChaiScript source: a line at a time using
`chai.eval(string)` and a file at a time using `chai.eval_file(fname)`
To make functions in your C++ code visible to scripts, they must be registered
with the scripting engine. To do so, call add:
chai.add(chaiscript::fun(&my_function), "my_function_name");
Once registered the function will be visible to scripts as "my_function_name"
Examples
========
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some
modifications to make it easier to use. For usage examples see the "samples"
directory, and for more in-depth look at the language, the unit tests in the
"unittests" directory cover the most ground.
For examples of how to register parts of your C++ application, see
"example.cpp" in the "src" directory. Example.cpp is verbose and shows every
possible way of working with the library. For further documentation generate
the doxygen documentation in the build folder or see the website
http://www.chaiscript.com.
The shortest complete example possible follows:
/// main.cpp
#include <chaiscript/chaiscript.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@@ -1,55 +0,0 @@
ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details.
[Introduction]
ChaiScript is one of the only embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques, working with the developer like he expects it to work. Being a native C++ application, it has some advantages over existing embedded scripting languages:
1) It uses a header-only approach, which makes it easy to integrate with existing projects.
2) It maintains type safety between your C++ application and the user scripts.
3) It supports a variety of C++ techniques including callbacks, overloaded functions, class methods, and stl containers.
[Requirements]
ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
[Usage]
* Add the ChaiScript include directory to your project's header search path
* Add "#include <chaiscript/chaiscript.hpp> to your source file
* Instantiate the ChaiScript engine in your application. For example, create a new engine with the name 'chai' like so: "chaiscript::ChaiScript chai"
Once instantiated, the engine is ready to start running ChaiScript source. You have two main options for processing ChaiScript source: a line at a time using "chai.evaluate_string(string)" and a file at a time using "chai.evaluate_file(fname)"
To make functions in your C++ code visible to scripts, they must be registered with the scripting engine. To do so, call add:
chai.add(chaiscript::fun(&my_function), "my_function_name");
Once registered the function will be visible to scripts as "my_function_name"
[Examples]
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some modifications to make it easier to use. For usage examples see the "samples" directory, and for more in-depth look at the language, the unit tests in the "unittests" directory cover the most ground.
For examples of how to register parts of your C++ application, see "example.cpp" in the "src" directory. Example.cpp is verbose and shows every possible way of working with the library. For further documentation generate the doxygen documentation in the build folder or see the website http://www.chaiscript.com.
The shortest complete example possible follows:
/// main.cpp
#include <chaiscript/chaiscript.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@@ -1,3 +1,15 @@
Changes since 4.1.1
* Add support for automatic conversion of arithmetic types when possible
and when no ambiguous method dispatch exists.
Changes since 4.1.0
* Fix missed gcc build error in 4.1.0
Changes since 4.0.0
* Fix sizing of numeric constants to match that of the C++ standard
* Add support for u,ll,l,f suffixes for numeric constants
* Siginificant improvement in error reporting
Changes since 3.1.0 Changes since 3.1.0
* svenstaro: Unused variables and CMake consistency fixes * svenstaro: Unused variables and CMake consistency fixes
* Added support for returning pointers from functions (#13) * Added support for returning pointers from functions (#13)

View File

@@ -141,7 +141,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Creating a functor on the stack and using it immediatly //Creating a functor on the stack and using it immediatly
int x = chai.eval<boost::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6); int x = chai.eval<boost::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
log("Functor test output", boost::lexical_cast<std::string>(x)); std::stringstream ss;
ss << x;
log("Functor test output", ss.str());
chai.add(var(boost::shared_ptr<int>()), "nullvar"); chai.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())"); chai("print(\"This should be true.\"); print(nullvar.is_var_null())");

View File

@@ -80,7 +80,18 @@ std::string get_next_command() {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw ) { if ( input_raw ) {
add_history(input_raw); add_history(input_raw);
retval = boost::trim_copy_if(std::string(input_raw),boost::is_any_of(" \t")); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos+1, std::string::npos);
}
retval = val;
::free(input_raw); ::free(input_raw);
} }
} }
@@ -219,18 +230,7 @@ int main(int argc, char *argv[])
} }
} }
catch (const chaiscript::exception::eval_error &ee) { catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.pretty_print();
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 (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; std::cout << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@@ -1,40 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <chaiscript/chaiscript.hpp>
#include <boost/thread.hpp>
void do_work(chaiscript::ChaiScript &c)
{
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
std::string name = "MyVar" + boost::lexical_cast<std::string>(rand());
c.add(chaiscript::var(5), name);
c("use(\"work.chai\"); do_chai_work(10000);");
}
int main(int argc, char *argv[]) {
std::string input;
chaiscript::ChaiScript chai;
//chai.add_shared_object(chaiscript::Boxed_Value(10000), "num_iterations");
std::vector<boost::shared_ptr<boost::thread> > threads;
for (int i = 0; i < argc - 1; ++i)
{
threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai)))));
}
for (int i = 0; i < argc - 1; ++i)
{
threads[i]->join();
}
}

View File

@@ -1,10 +0,0 @@
def do_chai_work(num_iters)
{
var i = 0;
for (var k = 0; k<num_iters * 10; ++k)
{
i += k;
}
print(i);
}

View File

@@ -0,0 +1,58 @@
// Tests to make sure that type conversions happen only when they should
#include <chaiscript/chaiscript.hpp>
void f1(int)
{
}
void f4(std::string)
{
}
void f2(int)
{
}
void f3(double)
{
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f1), "f1");
chai.add(chaiscript::fun(&f2), "f2");
chai.add(chaiscript::fun(&f3), "f2");
chai.add(chaiscript::fun(&f1), "f3");
chai.add(chaiscript::fun(&f4), "f3");
// no overloads
chai.eval("f1(0)");
chai.eval("f1(0l)");
chai.eval("f1(0ul)");
chai.eval("f1(0ll)");
chai.eval("f1(0ull)");
chai.eval("f1(0.0)");
chai.eval("f1(0.0f)");
chai.eval("f1(0.0l)");
// expected overloads
chai.eval("f2(1)");
chai.eval("f2(1.0)");
// 1 non-arithmetic overload
chai.eval("f2(1.0)");
// this is the one call we expect to fail
try {
chai.eval("f2(1.0l)");
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
// if the last one did not throw, we failed
return EXIT_FAILURE;
}

View File

@@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
extern "C"
{
int dosomething(int i)
{
return i % 2;
}
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&dosomething), "dosomething");
return chai.eval<int>("dosomething(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE;
}

View File

@@ -0,0 +1,111 @@
// Tests to make sure no arity, dispatch or guard errors leak up past eval
#include <chaiscript/utility/utility.hpp>
int test_one(const int &)
{
return 1;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&test_one), "test_fun");
chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} ");
bool eval_error = true;
// Dot notation
try {
// non-existant function
chai.eval("\"test\".test_one()");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong parameter type
chai.eval("\"test\".test_fun()");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong number of parameters
chai.eval("\"test\".test_fun(1)");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// guard failure
chai.eval("\"test\".guard_fun(1)");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// regular notation
try {
// non-existant function
chai.eval("test_one(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong parameter type
chai.eval("test_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong number of parameters
chai.eval("test_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// guard failure
chai.eval("guard_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// index operator
try {
chai.eval("var a = [1,2,3]; a[\"bob\"];");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// unary operator
try {
chai.eval("++\"bob\"");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// binary operator
try {
chai.eval("\"bob\" + 1");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
if (eval_error)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,90 @@
// Tests to make sure that the order in which function dispatches occur is correct
#include <chaiscript/chaiscript.hpp>
#define TEST_LITERAL(v) test_literal(v, #v)
template<typename T>
bool test_literal(T val, const std::string &str)
{
chaiscript::ChaiScript chai;
T val2 = chai.eval<T>(str);
std::cout << "Comparing : " << val << " " << val2 << std::endl;
return val == val2;
}
int main()
{
if( TEST_LITERAL(0xF)
&& TEST_LITERAL(0xFF)
&& TEST_LITERAL(0xFFF)
&& TEST_LITERAL(0xFFFF)
&& TEST_LITERAL(0xFFFFF)
&& TEST_LITERAL(0xFFFFFF)
&& TEST_LITERAL(0xFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL(01)
&& TEST_LITERAL(017)
&& TEST_LITERAL(0177)
&& TEST_LITERAL(01777)
&& TEST_LITERAL(017777)
&& TEST_LITERAL(0177777)
&& TEST_LITERAL(01777777)
&& TEST_LITERAL(017777777)
&& TEST_LITERAL(0177777777)
&& TEST_LITERAL(01777777777)
&& TEST_LITERAL(017777777777)
&& TEST_LITERAL(0177777777777)
&& TEST_LITERAL(01777777777777)
&& TEST_LITERAL(017777777777777)
&& TEST_LITERAL(0177777777777777)
&& TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777)
&& TEST_LITERAL(0177777777777777777)
&& TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777)
&& TEST_LITERAL(0177777777777777777777)
&& TEST_LITERAL(01777777777777777777777)
&& TEST_LITERAL(1)
&& TEST_LITERAL(17)
&& TEST_LITERAL(177)
&& TEST_LITERAL(1777)
&& TEST_LITERAL(17777)
&& TEST_LITERAL(177777)
&& TEST_LITERAL(1777777)
&& TEST_LITERAL(17777777)
&& TEST_LITERAL(177777777)
&& TEST_LITERAL(1777777777)
&& TEST_LITERAL(17777777777)
&& TEST_LITERAL(177777777777)
&& TEST_LITERAL(1777777777777)
&& TEST_LITERAL(17777777777777)
&& TEST_LITERAL(177777777777777)
&& TEST_LITERAL(1777777777777777)
&& TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777)
)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -1 +1,29 @@
assert_equal([true, false, true], map([1,2,3], odd)) assert_equal([true, false, true], map([1,2,3], odd))
var m = ["a":1, "b":2];
assert_equal(1, m.count("a"))
assert_equal(0, m.count("c"))
assert_equal(1, m.erase("a"))
assert_equal(1, m.size())
assert_equal(0, m.erase("a"))
assert_equal(1, m.size());
var m2 = ["c":3, "b":4]
m.insert(m2);
assert_equal(3, m["c"])
// The inserted values do not overwrite the existing ones
assert_equal(2, m["b"])
assert_equal(2, m.size())
var v = "bob";
m.insert_ref(Map_Pair("d", v))
assert_equal("bob", m["d"])
v = "bob2"
assert_equal("bob2", m["d"])

View File

@@ -0,0 +1,101 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <algorithm>
#include <chaiscript/chaiscript.hpp>
#include <boost/thread.hpp>
int expected_value(int num_iters)
{
int i = 0;
for (int k = 0; k<num_iters * 10; ++k)
{
i += k;
}
return i;
}
void do_work(chaiscript::ChaiScript &c, int id)
{
std::stringstream ss;
ss << "MyVar" << rand();
c.add(chaiscript::var(5), ss.str());
ss.str("");
ss << id;
c.use("multithreaded_work.inc");
c("do_chai_work(4000, " + ss.str() + ");");
}
int main()
{
// Disable deprecation warning for getenv call.
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
std::vector<std::string> modulepaths;
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
chaiscript::ChaiScript chai(modulepaths,usepaths);
std::vector<boost::shared_ptr<boost::thread> > threads;
// Ensure at least two, but say only 7 on an 8 core processor
int num_threads = std::max<unsigned int>(boost::thread::hardware_concurrency() - 1, 2u);
for (int i = 0; i < num_threads; ++i)
{
threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai), i))));
}
for (int i = 0; i < num_threads; ++i)
{
threads[i]->join();
}
for (int i = 0; i < num_threads; ++i)
{
std::stringstream ss;
ss << i;
if (chai.eval<int>("getvalue(" + ss.str() + ")") != expected_value(4000))
{
return EXIT_FAILURE;
}
if (chai.eval<int>("getid(" + ss.str() + ")") != i)
{
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,15 @@
def do_chai_work(num_iters, id)
{
var i = 0;
for (var k = 0; k<num_iters * 10; ++k)
{
if (k == 1000)
{
eval("def getid(id) : id == " + to_string(id) + " { return " + to_string(id) + "}");
}
i += k;
}
eval("def getvalue(id) : id == " + to_string(id) + " { return " + to_string(i) + "}");
}

View File

@@ -0,0 +1,11 @@
assert_equal(true, int_type.bare_equal(1.get_type_info()))
assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info()))
assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info()))
assert_equal(true, long_type.bare_equal(1l.get_type_info()))
assert_equal(true, int64_t_type.bare_equal(1ll.get_type_info()))
assert_equal(true, uint64_t_type.bare_equal(1ull.get_type_info()))
assert_equal(true, double_type.bare_equal(1.6.get_type_info()))
assert_equal(true, float_type.bare_equal(1.6f.get_type_info()))
assert_equal(true, long_double_type.bare_equal(1.6l.get_type_info()))

View File

@@ -0,0 +1,61 @@
#include <chaiscript/chaiscript.hpp>
int myfun()
{
return 2;
}
int main()
{
chaiscript::ChaiScript chai;
// save the initial state of globals and locals
chaiscript::ChaiScript::State firststate = chai.get_state();
std::map<std::string, chaiscript::Boxed_Value> locals = chai.get_locals();
// add some new globals and locals
chai.add(chaiscript::var(1), "i");
chai.add(chaiscript::fun(&myfun), "myfun");
bool didcall = chai.eval<int>("myfun()") == 2;
bool hadi = chai.eval<int>("i") == 1;
chai.set_state(firststate);
// set state should have reverted the state of the functions and dropped
// the 'myfun'
bool didnotcall = false;
try {
chai.eval<int>("myfun()");
} catch (const chaiscript::exception::eval_error &) {
didnotcall = true;
}
// set state should not affect the local variables
bool stillhasid = chai.eval<int>("i") == 1;
// After resetting the locals we expect the 'i' to be gone
chai.set_locals(locals);
bool nolongerhasid = false;
try {
chai.eval<int>("i");
} catch (const chaiscript::exception::eval_error &) {
nolongerhasid = true;
}
if (didcall && hadi && didnotcall && stillhasid && nolongerhasid)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,60 @@
#include <chaiscript/chaiscript.hpp>
int dosomething(int i)
{
return i + 2;
}
int dosomethingelse(int i)
{
return i * 2;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&dosomething), "dosomething");
chai.add(chaiscript::var(1), "i");
for (int i = 0; i < 10; ++i)
{
chaiscript::ChaiScript chai2;
chai2.add(chaiscript::fun(&dosomethingelse), "dosomethingelse");
std::stringstream ss;
ss << i;
if (chai.eval<int>("dosomething(" + ss.str() + ")") != i + 2)
{
return EXIT_FAILURE;
}
if (chai2.eval<int>("dosomethingelse(" + ss.str() + ")") != i * 2)
{
return EXIT_FAILURE;
}
try {
chai2.eval("dosomething(1)");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
try {
chai2.eval("i");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
try {
chai.eval("dosomethingelse(1)");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
}
}

View File

@@ -0,0 +1 @@
assert_equal("3ab", "123abab".substr(2,3))