Extending C++Script

There are different ways to extend C++Script depending on your needs, as documented below.

Method 1: Implement within C++Script

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;
}

Method 2: Use a dispatcher

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;
}

Method 3: Wrap a C++ object

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;
}

Method 4: Implement a var_impl

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;
}

Method 5: Implement a shared_var_impl

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.

Supported platforms

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.

How to contribute

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.

Release checklist

  1. Ensure that all new functionality has unit tests.
  2. Ensure that existing unit tests run.
  3. Check build on tested platforms.
  4. Rename version number in sources, configuration files and manual.
  5. Doxygen the output and review.
  6. Build the tar and zip.
  7. Create a SVN branch for the new version.
  8. Copy tar, zip, doxygen and manual to the web site.
  9. Update the web pages with the new version and release notes.