From 906140ec789f4258f9ff862c840b4634e4dcb1fa Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 8 Nov 2010 05:22:15 +0000 Subject: [PATCH] Find and fix bug in handling of bound function types_infos and arity. Remote outdated samples. Move working samples into samples folder and make part of build process. Make building of samples optional. Closing #107 --- CMakeLists.txt | 9 + contrib/test/callbacktest.cpp | 69 ------ contrib/test/dispatchkit_test.cpp | 212 ------------------ contrib/test/dispatchkit_unittest.cpp | 23 -- contrib/test/sensors.cpp | 148 ------------ .../dispatchkit/proxy_functions.hpp | 34 ++- samples/bind.chai | 22 -- {src => samples}/example.cpp | 0 {src => samples}/memory_leak_test.cpp | 7 +- samples/sensors.chai | 70 ------ src/main.cpp | 2 +- unittests/bind2.chai | 34 +++ 12 files changed, 78 insertions(+), 552 deletions(-) delete mode 100644 contrib/test/callbacktest.cpp delete mode 100644 contrib/test/dispatchkit_test.cpp delete mode 100644 contrib/test/dispatchkit_unittest.cpp delete mode 100644 contrib/test/sensors.cpp delete mode 100644 samples/bind.chai rename {src => samples}/example.cpp (100%) rename {src => samples}/memory_leak_test.cpp (91%) delete mode 100644 samples/sensors.chai create mode 100644 unittests/bind2.chai diff --git a/CMakeLists.txt b/CMakeLists.txt index 20efbc73..57756405 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8) project(chaiscript) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) +option(BUILD_SAMPLES "Build Samples Folder" FALSE) list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn") @@ -97,6 +98,14 @@ include_directories(${Boost_INCLUDE_DIR}) add_executable(chai src/main.cpp) target_link_libraries(chai ${LIBS}) +if (BUILD_SAMPLES) + add_executable(example samples/example.cpp) + target_link_libraries(example ${LIBS}) + add_executable(memory_leak_test samples/memory_leak_test.cpp) + target_link_libraries(memory_leak_test ${LIBS}) +endif() + + add_library(stl_extra MODULE src/stl_extra.cpp) target_link_libraries(stl_extra ${LIBS}) diff --git a/contrib/test/callbacktest.cpp b/contrib/test/callbacktest.cpp deleted file mode 100644 index bbb68cd4..00000000 --- a/contrib/test/callbacktest.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009, Jonathan Turner (jonathan@emptycrate.com) -// and Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#include - -#include "function_call.hpp" -#include "chaiscript.hpp" -#include - -struct Callback_Handler -{ - typedef std::vector, - boost::function > > Callbacks; - - Callbacks m_callbacks; - - void add_callbacks(boost::shared_ptr t_name, - boost::shared_ptr t_value) - { - m_callbacks.push_back( - std::make_pair(dispatchkit::build_function_caller(t_name), - dispatchkit::build_function_caller(t_value) - ) - ); - } - - void do_callbacks() - { - int i=1; - for (Callbacks::iterator itr = m_callbacks.begin(); - itr != m_callbacks.end(); - ++itr) - { - std::cout << "Name: " << itr->first() << " = " << itr->second(i) << std::endl; - ++i; - } - } -}; - -int main(int argc, char *argv[]) { - - chaiscript::ChaiScript_Engine chai; - - Callback_Handler cb_handler; - chai.get_eval_engine().add_object("cb_handler", boost::ref(cb_handler)); - dispatchkit::register_function(chai.get_eval_engine(), &Callback_Handler::add_callbacks, "add_callbacks"); - - for (int i = 1; i < argc; ++i) { - try { - dispatchkit::Boxed_Value val = chai.evaluate_file(argv[i]); - } - catch (std::exception &e) { - std::cerr << "Could not open: " << argv[i] << std::endl; - exit(1); - } - } - - cb_handler.do_callbacks(); - - boost::function f = - dispatchkit::build_functor - (chai, "function(x, y) { return x + y }"); - - std::cout << "Functor call: " << f("Hello", " World") << std::endl; -} - diff --git a/contrib/test/dispatchkit_test.cpp b/contrib/test/dispatchkit_test.cpp deleted file mode 100644 index 0eab9519..00000000 --- a/contrib/test/dispatchkit_test.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009, Jonathan Turner (jonathan@emptycrate.com) -// and Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace dispatchkit; - -struct Test -{ - Test(const std::string &s) - : number(-25), message(s) - { - std::cout << "Test class constructed with value: " << s << std::endl; - } - - void show_message() - { - std::cout << "Constructed Message: " << message << std::endl; - } - - std::string &get_message() - { - return message; - } - - int number; - - std::string message; -}; - - - -Boxed_Value named_func_call(Dispatch_Engine &ss, - const std::string &nametocall, const std::vector ¶ms) -{ - if (params.size() == 2) - { - return dispatch(ss.get_function(nametocall), params); - } else { - throw std::runtime_error("Invalid num params"); - } -} - -// A function that takes a dynamic list of params -// and calls a bunch of conversion functions on them and -// returns the result as a boxed_value -Boxed_Value dynamic_function(Dispatch_Engine &ss, const std::string &name, - const std::vector ¶ms) -{ - if (name == "concat_string") - { - Boxed_Value result; - - //Return a void if there is nothing in the array - if (params.size() == 0) - { - return result; - } else { - //else, prepopulate the result with a string conversion of the first - //param - result = - dispatch(ss.get_function("to_string"), Param_List_Builder() << params[0]); - } - - //Then, loop over all remaining params, converting them to strings and adding - //them to the result. This example maybe bette served with a string += operator - //implementation, but it works. - for (size_t i = 1; i < params.size(); ++i) - { - result = - dispatch(ss.get_function("+"), Param_List_Builder() << result << - dispatch(ss.get_function("to_string"), Param_List_Builder() << params[i])); - } - - return result; - } else { - throw std::runtime_error("Unknown function call"); - } -} - -void test(const std::string &p) -{ - std::cout << "Test: " << p << std::endl; -} - -//Test main -int main() -{ - Dispatch_Engine ss; - Bootstrap::bootstrap(ss); - bootstrap_vector >(ss, "VectorInt"); - dump_system(ss); - - //Calling a function by name and allowing the built in dispatch mechanism to - //choose the most appropriate version of the function - Boxed_Value addresult = dispatch(ss.get_function("+"), Param_List_Builder() << double(5.1) << double(10.3)); - - //Using the cast to unbox the resultant value and output it - std::cout << boxed_cast(addresult) << std::endl; - - //Using the Boxed_Value as input to another function, again with automatic dispatch. - //This time we will not bother saving the result and will instead send it straight out - std::cout << boxed_cast( - dispatch(ss.get_function("*"), Param_List_Builder() << 2 << addresult) - ) << std::endl; - - //Register a new function, this one with typing for us, so we don't have to ubox anything - //right here - - //Now we have a print method, let's try to print out the earlier example: - //so, we dispatch the to_string and pass its result as a param to "print" - //In this example we don't bother with temporaries and we don't have to know - //anything about types - dispatch(ss.get_function("print_string"), - Param_List_Builder() << dispatch(ss.get_function("to_string"), Param_List_Builder() << addresult)); - - // Now we are going to register a new dynamic function, - // when this function is called the objects are not unboxed, but passed - // in in their boxed state - ss.register_function(boost::shared_ptr(new Dynamic_Proxy_Function(boost::bind(&dynamic_function, boost::ref(ss), "concat_string", _1))), "concat_string"); - - - // Call our newly defined dynamic function with 10 parameters, then send - // its output to the "print" function - dispatch(ss.get_function("print_string"), - Param_List_Builder() << dispatch(ss.get_function("concat_string"), - Param_List_Builder() << std::string("\n\t") << std::string("The Value Was: ") - << double(42.5) << std::string(".") - << '\n' - << '\t' << std::string("The old value was: ") - << addresult << '.' << '\n' )); - - - - - //Register some local methods of the "Test" class - ss.register_function(build_constructor(), "Test"); - - register_function(ss, &Test::get_message, "get_message"); - register_function(ss, &Test::show_message, "show_message"); - register_member(ss, &Test::number, "number"); - - //Create a new object using the "Test" constructor, passing the param "Yo". - //Then, add the new object to the system with the name "testobj2" - ss.add_object("testobj2", - dispatch(ss.get_function("Test"), Param_List_Builder() << std::string("Yo"))); - - // Look up and store a reference to our new object - std::vector sos; - sos.push_back(ss.get_object("testobj2")); - - //Build a bound function proxy for calling the script handled function - boost::function show_message = - build_function_caller(ss.get_function("show_message")); - - Test &t = boxed_cast(ss.get_object("testobj2")); - - //Print the message the object was created with - show_message(t); - - //Now, get a reference to the object's stored message - Boxed_Value stringref = dispatch(ss.get_function("get_message"), sos); - - //Unbox it using boxed_cast - std::string &sr = boxed_cast(stringref); - - //Update the value of the reference - sr = "Bob Updated The message"; - - //Now, get a reference to the object's stored number - Boxed_Value numberref= dispatch(ss.get_function("number"), sos); - - //Unbox it using boxed_cast - int &ir = boxed_cast(numberref); - - std::cout << "Number: " << ir << std::endl; - - //Now, prove that the reference was successfully acquired - //and we are able to peek into the boxed types - show_message(t); - - - // Finally, we are going to register some named function aliases, for - // the fun of it - ss.register_function(boost::shared_ptr( - new Dynamic_Proxy_Function(boost::bind(&named_func_call, boost::ref(ss), "+", _1))), "add"); - - //Call our newly named "add" function (which in turn dispatches +) - - std::cout << "Result of add function: " << - boxed_cast(dispatch(ss.get_function("add"), Param_List_Builder() << 5 << 2)) - << std::endl; - - - ss.set_object("myfunc", boost::shared_ptr(new Proxy_Function_Impl >(&test))); - - dispatch(ss.get_function("myfunc"), Param_List_Builder() << std::string("hello function variable")); - -} - diff --git a/contrib/test/dispatchkit_unittest.cpp b/contrib/test/dispatchkit_unittest.cpp deleted file mode 100644 index 188235e3..00000000 --- a/contrib/test/dispatchkit_unittest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009, Jonathan Turner (jonathan@emptycrate.com) -// and Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#include "dispatchkit.hpp" -#include "bootstrap.hpp" - -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE boxedcpp_unittests -#include - -BOOST_AUTO_TEST_CASE( add_operators ) -{ - using namespace dispatchkit; - - Dispatch_Engine ss; - Bootstrap::bootstrap(ss); - dump_system(ss); - - BOOST_CHECK_EQUAL(boxed_cast(dispatch(ss.get_function("+"), Param_List_Builder() << double(5.1) << double(10.3))), 15.4); -} diff --git a/contrib/test/sensors.cpp b/contrib/test/sensors.cpp deleted file mode 100644 index 84b04648..00000000 --- a/contrib/test/sensors.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009, Jonathan Turner (jonathan@emptycrate.com) -// and Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#include - -#include "chaiscript.hpp" -#include "function_call.hpp" -#include -#include -#include - - -std::string load_text_file(const std::string &filename) -{ - std::ifstream infile(filename.c_str()); - - std::string str; - - std::string result; - - while (std::getline(infile, str)) - { - result += str + "\n"; - } - - return result; -} - -std::vector regex_search(const std::string &str, const std::string ®ex) -{ - boost::smatch matches; - boost::regex_search(str, matches, boost::regex(regex)); - - std::vector results; - - for (unsigned int i = 0; i < matches.size(); ++i) - { - results.push_back(dispatchkit::Boxed_Value(std::string(matches.str(i)))); - } - - return results; -} - -struct Sensor_Manager -{ - struct Sensor - { - int milliseconds; - dispatchkit::Boxed_Value state_object; - boost::function sensor; - boost::posix_time::ptime next_run; - - Sensor(int t_milliseconds, dispatchkit::Boxed_Value t_state_object, - boost::function t_sensor) - : milliseconds(t_milliseconds), state_object(t_state_object), sensor(t_sensor), - next_run(boost::posix_time::microsec_clock::universal_time() - + boost::posix_time::milliseconds(milliseconds)) - { - } - - std::pair get_value() - { - next_run = boost::posix_time::microsec_clock::universal_time() - + boost::posix_time::milliseconds(milliseconds); - - return std::make_pair(boost::posix_time::microsec_clock::universal_time(), - sensor(state_object)); - } - }; - - std::map m_sensors; - - //sensor_manager.add_sensor("CPU", 1000, global_state, function(state) { update_state(state); state["CPU"]; } ) - void add_sensor(const std::string &t_name, int t_milliseconds, dispatchkit::Boxed_Value t_state_object, - boost::shared_ptr t_func) - { - m_sensors.insert( - std::make_pair(t_name, - Sensor(t_milliseconds, t_state_object, - dispatchkit::build_function_caller(t_func) - ) - ) - ); - } - - - std::vector > run_sensors() - { - std::vector > results; - - boost::posix_time::ptime t(boost::posix_time::microsec_clock::universal_time()); - - for (std::map::iterator itr = m_sensors.begin(); - itr != m_sensors.end(); - ++itr) - { - if (itr->second.next_run <= t) - { - results.push_back(std::make_pair(itr->first, itr->second.get_value().second)); - } - } - - return results; - } - -}; - - -int main(int argc, char *argv[]) { - - chaiscript::ChaiScript_Engine chai; - - Sensor_Manager sensor_manager; - chai.get_eval_engine().add_object("sensor_manager", boost::ref(sensor_manager)); - - dispatchkit::register_function(chai.get_eval_engine(), &Sensor_Manager::add_sensor, "add_sensor"); - dispatchkit::register_function(chai.get_eval_engine(), ®ex_search, "regex_search"); - dispatchkit::register_function(chai.get_eval_engine(), &load_text_file, "load_text_file"); - - - - for (int i = 1; i < argc; ++i) { - try { - chai.evaluate_file(argv[i]); - } - catch (std::exception &e) { - std::cerr << "Could not open: " << argv[i] << std::endl; - exit(1); - } - } - - while (true) - { - usleep(1000); - std::vector > sensor_data = sensor_manager.run_sensors(); - - for (std::vector >::iterator itr = sensor_data.begin(); - itr != sensor_data.end(); - ++itr) - { - std::cout << "Sensor: " << itr->first << " value: " << itr->second << std::endl; - } - } -} - diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 85eaf980..82ac87c6 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -304,15 +304,15 @@ namespace chaiscript public: Bound_Function(const Const_Proxy_Function &t_f, const std::vector &t_args) - : Proxy_Function_Base(std::vector()), - m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - static_cast(m_args.size()))) + : Proxy_Function_Base(build_param_type_info(t_f, t_args)), + m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:get_param_types().size()-1) { - assert(m_f->get_arity() < 0 || m_f->get_arity() >= static_cast(m_args.size())); + assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); } - virtual bool operator==(const Proxy_Function_Base &) const + virtual bool operator==(const Proxy_Function_Base &t_f) const { - return false; + return &t_f == this; } virtual ~Bound_Function() {} @@ -375,10 +375,32 @@ namespace chaiscript virtual std::string annotation() const { - return ""; + return "Bound: " + m_f->annotation(); } protected: + static std::vector build_param_type_info(const Const_Proxy_Function &t_f, + const std::vector &t_args) + { + assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); + if (t_f->get_arity() < 0) { return std::vector(); } + + std::vector types = t_f->get_param_types(); + assert(types.size() == t_args.size() + 1); + + std::vector retval; + retval.push_back(types[0]); + for (size_t i = 0; i < types.size()-1; ++i) + { + if (t_args[i].get_type_info() == detail::Get_Type_Info::get()) + { + retval.push_back(types[i+1]); + } + } + + return retval; + } + virtual Boxed_Value do_call(const std::vector ¶ms) const { return (*m_f)(build_param_list(params)); diff --git a/samples/bind.chai b/samples/bind.chai deleted file mode 100644 index e7aea7e1..00000000 --- a/samples/bind.chai +++ /dev/null @@ -1,22 +0,0 @@ - -def add(x, y) -{ - return x + y; -} - -var b = bind(add, 2, _); -var c = bind(b, 3); - -print(b(4)); -print(c()); - - -def concat(a,b,c,d) -{ - return to_string(a) + to_string(b) + to_string(c) + to_string(d); -} - -var d = bind(concat, _, " Hello ", _, " World "); -print(d(1, 3)); -//This checks to make sure arity is handled correctly: -//print(d(1, 3, 4)); diff --git a/src/example.cpp b/samples/example.cpp similarity index 100% rename from src/example.cpp rename to samples/example.cpp diff --git a/src/memory_leak_test.cpp b/samples/memory_leak_test.cpp similarity index 91% rename from src/memory_leak_test.cpp rename to samples/memory_leak_test.cpp index 571d9fef..4565609f 100644 --- a/src/memory_leak_test.cpp +++ b/samples/memory_leak_test.cpp @@ -1,6 +1,11 @@ #include #include "chaiscript/chaiscript.hpp" +#ifdef READLINE_AVAILABLE +#include +#include +#endif + using namespace chaiscript; @@ -54,7 +59,7 @@ public: -int main(int argc, char *argv[]) { +int main(int /*argc*/, char * /*argv*/[]) { test myChai; diff --git a/samples/sensors.chai b/samples/sensors.chai deleted file mode 100644 index 2cf108ff..00000000 --- a/samples/sensors.chai +++ /dev/null @@ -1,70 +0,0 @@ - - -def initialize_cpu_sensor(state, cpuname, sensor_manager) -{ - state[cpuname] = 0.0; - state[cpuname + ".user"] = 0.0; - state[cpuname + ".nice"] = 0.0; - state[cpuname + ".system"] = 0.0; - state[cpuname + ".idle"] = 0.0; - state[cpuname + ".iowait"] = 0.0; - state[cpuname + ".irq"] = 0.0; - state[cpuname + ".softirq"] = 0.0; -} - -def update_cpu_state(state, statfile, cpuname) -{ - var regex = cpuname + "\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)"; - var strs = regex_search(statfile, regex); - - var user = to_double(strs[1]); - var nice = to_double(strs[2]); - var system = to_double(strs[3]); - var idle = to_double(strs[4]); - var iowait = to_double(strs[5]); - var irq = to_double(strs[6]); - var softirq = to_double(strs[7]); - - var userd = user - state[cpuname + ".user"]; - var niced = nice - state[cpuname + ".nice"]; - var systemd = system - state[cpuname + ".system"]; - var idled = idle - state[cpuname + ".idle"]; - var iowaitd = iowait - state[cpuname + ".iowait"]; - var irqd = irq - state[cpuname + ".irq"]; - var softirqd = softirq - state[cpuname + ".softirq"]; - - var totalticks = userd + niced + systemd + idled + iowaitd + irqd + softirqd; - - state[cpuname] = (totalticks - idled) / totalticks - - state[cpuname + ".user"] = user; - state[cpuname + ".nice"] = nice; - state[cpuname + ".system"] = system; - state[cpuname + ".idle"] = idle; - state[cpuname + ".iowait"] = iowait; - state[cpuname + ".irq"] = irq; - state[cpuname + ".softirq"] = softirq; -} - -# annotation -def update_state(state) -{ - var file = load_text_file("/proc/stat"); - - update_cpu_state(state, file, "cpu"); - update_cpu_state(state, file, "cpu0"); - update_cpu_state(state, file, "cpu1"); -} - -//dump_system() - -var global_state = Map() - -initialize_cpu_sensor(global_state, "cpu", sensor_manager); -initialize_cpu_sensor(global_state, "cpu0", sensor_manager); -initialize_cpu_sensor(global_state, "cpu1", sensor_manager); - -sensor_manager.add_sensor("cpu", 500, global_state, fun(state) { update_state(state); state["cpu"]; } ) -sensor_manager.add_sensor("cpu0", 500, global_state, fun(state) { state["cpu0"]; } ) -sensor_manager.add_sensor("cpu1", 500, global_state, fun(state) { state["cpu1"]; } ) - diff --git a/src/main.cpp b/src/main.cpp index 6a5fe599..9057bdd2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { catch (chaiscript::Eval_Error &ee) { std::cout << ee.what(); if (ee.call_stack.size() > 0) { - std::cout << "during evaluation at (" << ee.call_stack[0]->filename << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; + std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; for (unsigned int j = 1; j < ee.call_stack.size(); ++j) { std::cout << std::endl; std::cout << " from " << ee.call_stack[j]->filename << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; diff --git a/unittests/bind2.chai b/unittests/bind2.chai new file mode 100644 index 00000000..0b8ddde3 --- /dev/null +++ b/unittests/bind2.chai @@ -0,0 +1,34 @@ + +def add(x, y) +{ + return x + y; +} + +assert_equal(2, add.get_arity()); + +var b = bind(add, 2, _); + +assert_equal(1, b.get_arity()); + +var c = bind(b, 3); + +assert_equal(0, c.get_arity()); + +assert_equal(6, b(4)); +assert_equal(5, c()); + +def concat2(a,b,c,d) +{ + return to_string(a) + to_string(b) + to_string(c) + to_string(d); +} + +var d = bind(concat2, _, " Hello ", _, " World"); +assert_equal(2, d.get_arity()); + +assert_equal("1 Hello 3 World", d(1,3)); + +var e = bind(`<`, _, 5); +var types = e.get_param_types(); +assert_equal(2, types.size()); +assert_equal(true, types[0].bare_equal(bool_type)); +