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
This commit is contained in:
Jason Turner
2010-11-08 05:22:15 +00:00
parent e75a354a04
commit 906140ec78
12 changed files with 78 additions and 552 deletions

View File

@@ -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})

View File

@@ -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 <iostream>
#include "function_call.hpp"
#include "chaiscript.hpp"
#include <boost/function.hpp>
struct Callback_Handler
{
typedef std::vector<std::pair<boost::function<std::string ()>,
boost::function<double (int)> > > Callbacks;
Callbacks m_callbacks;
void add_callbacks(boost::shared_ptr<dispatchkit::Proxy_Function> t_name,
boost::shared_ptr<dispatchkit::Proxy_Function> t_value)
{
m_callbacks.push_back(
std::make_pair(dispatchkit::build_function_caller<std::string ()>(t_name),
dispatchkit::build_function_caller<double (int)>(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<std::string (const std::string&, const std::string &)> f =
dispatchkit::build_functor<std::string (const std::string &, const std::string &)>
(chai, "function(x, y) { return x + y }");
std::cout << "Functor call: " << f("Hello", " World") << std::endl;
}

View File

@@ -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 <iostream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <chaiscript/dispatchkit/bootstrap.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
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<Boxed_Value> &params)
{
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<Boxed_Value> &params)
{
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<std::vector<int> >(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<double>(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<double>(
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<Proxy_Function>(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, const std::string &>(), "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<Boxed_Value> sos;
sos.push_back(ss.get_object("testobj2"));
//Build a bound function proxy for calling the script handled function
boost::function<void (Test &)> show_message =
build_function_caller<void (Test &)>(ss.get_function("show_message"));
Test &t = boxed_cast<Test &>(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<std::string &>(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<int &>(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<Proxy_Function>(
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<int>(dispatch(ss.get_function("add"), Param_List_Builder() << 5 << 2))
<< std::endl;
ss.set_object("myfunc", boost::shared_ptr<Proxy_Function>(new Proxy_Function_Impl<boost::function<void (const std::string &)> >(&test)));
dispatch(ss.get_function("myfunc"), Param_List_Builder() << std::string("hello function variable"));
}

View File

@@ -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/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE( add_operators )
{
using namespace dispatchkit;
Dispatch_Engine ss;
Bootstrap::bootstrap(ss);
dump_system(ss);
BOOST_CHECK_EQUAL(boxed_cast<int>(dispatch(ss.get_function("+"), Param_List_Builder() << double(5.1) << double(10.3))), 15.4);
}

View File

@@ -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 <iostream>
#include "chaiscript.hpp"
#include "function_call.hpp"
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/regex.hpp>
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<dispatchkit::Boxed_Value> regex_search(const std::string &str, const std::string &regex)
{
boost::smatch matches;
boost::regex_search(str, matches, boost::regex(regex));
std::vector<dispatchkit::Boxed_Value> 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<double (dispatchkit::Boxed_Value)> sensor;
boost::posix_time::ptime next_run;
Sensor(int t_milliseconds, dispatchkit::Boxed_Value t_state_object,
boost::function<double (dispatchkit::Boxed_Value)> 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<boost::posix_time::ptime, double> 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<std::string, Sensor> 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<dispatchkit::Proxy_Function> t_func)
{
m_sensors.insert(
std::make_pair(t_name,
Sensor(t_milliseconds, t_state_object,
dispatchkit::build_function_caller<double (dispatchkit::Boxed_Value)>(t_func)
)
)
);
}
std::vector<std::pair<std::string, double> > run_sensors()
{
std::vector<std::pair<std::string, double> > results;
boost::posix_time::ptime t(boost::posix_time::microsec_clock::universal_time());
for (std::map<std::string, Sensor>::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(), &regex_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<std::pair<std::string, double> > sensor_data = sensor_manager.run_sensors();
for (std::vector<std::pair<std::string, double> >::iterator itr = sensor_data.begin();
itr != sensor_data.end();
++itr)
{
std::cout << "Sensor: " << itr->first << " value: " << itr->second << std::endl;
}
}
}

View File

@@ -304,15 +304,15 @@ namespace chaiscript
public:
Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(std::vector<Type_Info>()),
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - static_cast<int>(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<int>(m_args.size()));
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(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<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
{
assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast<int>(t_args.size()));
if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); }
std::vector<Type_Info> types = t_f->get_param_types();
assert(types.size() == t_args.size() + 1);
std::vector<Type_Info> 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<Placeholder_Object>::get())
{
retval.push_back(types[i+1]);
}
}
return retval;
}
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
{
return (*m_f)(build_param_list(params));

View File

@@ -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));

View File

@@ -1,6 +1,11 @@
#include <iostream>
#include "chaiscript/chaiscript.hpp"
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#endif
using namespace chaiscript;
@@ -54,7 +59,7 @@ public:
int main(int argc, char *argv[]) {
int main(int /*argc*/, char * /*argv*/[]) {
test myChai;

View File

@@ -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"]; } )

View File

@@ -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 << ")";

34
unittests/bind2.chai Normal file
View File

@@ -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));