There are different ways to extend C++Script depending on your needs, as documented below.
This is the simplest method, where you just implement the functionality in C++Script itself. This example shows an example of a counter implemented using this method. e.g. (extension1.cpp)
#include <cppscript>var counter1_reset(var counter1)
{ counter1["value"]=0;}
var counter1_get(var counter1)
{ return counter1["value"]++;}
var counter1(var initial_value)
{ return object("counter1").extend ("reset", counter1_reset) ("get", counter1_get) ("value", initial_value);}
var script_main(var)
{ var counter = counter1(1);writeln( counter["get"]() );
writeln( counter["get"]() );
return 0;}
A dispatcher (created using the function dispatcher()) function provides a way for an object to implement the methods on a var. This is really just a change in syntax. e.g. (extension2.cpp)
#include <cppscript>var counter2_as_int(var counter2)
{ return counter2["value"]++;}
void counter2_clear(var counter2)
{ counter2["value"] = 0;}
var counter2(var initial_value)
{ return dispatcher( object("counter2").extend ("value", initial_value) ("as_int", counter2_as_int) ("clear", counter2_clear));
}
var script_main(var)
{ var counter = counter2(1);writeln( counter.as_int() );
writeln( counter.as_int() );
return 0;}
The function dynamic::create() creates a var containing a C++ value of any type, and var::as<>() accesses the C++ value. You can then create methods around that object. e.g. (extension3.cpp)
#include <cppscript>#include <dynamic/extensions.hpp>
class Counter{ int value;public:Counter(int initial_value) : value(initial_value)
{}
void reset() { value=0;}
int get() { return value++;}
};
var counter3_get(var counter3)
{ return counter3["value"].as<Counter>().get();}
void counter3_reset(var counter3)
{ counter3["value"].as<Counter>().reset();}
var counter3(var initial_value)
{ return object("counter3").extend ("value", create(Counter(initial_value))) ("get", counter3_get) ("reset", counter3_reset);}
var script_main(var)
{ var counter = counter3(1);writeln( counter["get"]() );
writeln( counter["get"]() );
return 0;}
The class dynamic::var_impl
is the pure virtual base class of all var
functionality. Derive from this base class and implement the methods you
need. This method is only suitable for small objects wrapping a single
pointer or value, since these classes are copied by value.
You create a var containing a
custom var_impl implementation by passing the
object to var's constructor.
See the Doxygen documentation for var_impl
for a description of these methods. The methods you must implement are:
e.g. (extension4.cpp)
#include <cppscript>#include <dynamic/extensions.hpp>
class Counter : public var_impl
{ int value;public:Counter( var initial_value ) : value(initial_value)
{}
int as_int()
{ return value++; }
void clear() { value=0; }
void copy_to(void*p) const
{ new(p) Counter(*this);}
std::string class_name()
{ return "Counter";}
};
var counter4(var initial_value)
{return create_impl( Counter(initial_value) );
}
var script_main(var)
{ var counter = counter4(1);writeln( counter.as_int() );
writeln( counter.as_int() );
return 0;}
The class dynamic::shared_var_impl
is the base class of all objects which are copied by reference (meaning that
copying the var does not copy the underlying object).
The advantage of these objects is that they are not restricted by size.
You assign a shared_var_impl to a var just by passing a pointer to the object to the
constructor of var.
The methods you must implement are:
e.g. (extension5.cpp)
#include <cppscript>#include <dynamic/extensions.hpp>
class Counter : public shared_var_impl
{ int value;public:Counter( var initial_value ) : value(initial_value)
{}
int as_int()
{ return value++; }
void clear() { value=0; }
std::string class_name()
{ return "Counter"; }
void mark_children(gc::garbage_collector&)
{}
};
var counter5(var initial_value)
{return new Counter(initial_value);
}
var script_main(var)
{ var counter = counter5(1);writeln( counter.as_int() );
writeln( counter.as_int() );
return 0;}
Your implementation can contain var member variables, but there's a catch. If these objects can eventually point back to your object, then you have a "loop" which isn't garbage collected. So you should call dynamic::var_impl::as_nonroot() [note that this mechanism is subject to change] to create a non-root variable. In that case, you must implement the mark_children() method to ensure that your members aren't collected by the garbage collector.
Builds are checked on these platforms:
Other platforms which are reported to work:
Platforms which don't work:
If you get a build working on a platform, please submit a patch.
Please submit suggestions and defects here. The todo
list contains ideas for future work. Please let me know what you are
up to so I can add you as a project member and make sure work isn't duplicated.
It might be more manageable to provide C++Script as a suite of
libraries rather than as a big lump.
Please send email to cppscript at calumgrant
dawt net.