Integration

Large projects

There will come a point where your single .cpp file gets too big and you need to split it up.  

Method 1: Pass several .cpp files to cppscript

The cppscript program can take several .cpp files on its command line.  You also want to declare your functions in header files (.hpp files).  Example:

foo1.cpp:

#include <cppscript>
#include <foo.hpp>
 
var script_main(var)
{
    f(12);
    return 0;
}

foo2.cpp:

#include <cppscript>
#include <foo.hpp>
 
void f(var i)
{
    writeln(i);
}

foo.hpp:

void f(var);

Method 2: #include your .cpp files

You can instead create a single .cpp file which #includes the other files.  e.g.

foo.cpp:

#include "foo1.cpp"
#include "foo2.cpp"

The benefit of this approach is that you have just one source file to pass to cppscript.  Compilation times could get very long though.

Method 3: Compile as C++

You can avoid using the cppscript program altogether, and just compile the program as C++.  Then you just use the normal C++ tools like make to build the project as any C++ project.  This is the recommended approach for large programs, and when C++Script is integrated with a C++ program.

Assuming g++, the command line for the previous example would be:

g++ foo1.cpp foo2.cpp -o foo -lcppscript

C++ integration

Header files and namespace

All C++Script's functions, and the var type, are actually in the dynamic namespace.

The main include file is <cppscript> (following the C++ standard's example of omitting the filename extension), which contains the statement using namespace dynamic  This is normally desired, but breaks the rule to avoid using namespace in header files.  The header file <dynamic/dynamic.hpp> does not have using namespace and should be used if there is a name clash.

The main include files to know about are

Libraries

The C++Script library is called dynamic, which may appear as libdynamic.a or libdynamic.lib on your platform.

Calling C and C++ from C++Script, and vice versa

This is trivially supported by compiling C++Script as C++.  C++ can call C++Script functions, and C++Script can use native C++ as needed.

It isn't possible to call C++Script directly from C.  You would need to write an extern "C" function.

Converting between var and C++ values

The var constructor takes a range of C++ values, including bool, char, wchar_t, int, double, char*, wchar_t*, std::string, std::wstring, functions of var, and fixed-size arrays.  These values get converted automatically to a var of the appropriate type.

The method var::operator bool() converts the var to a boolean (same as var::as_bool()), and var::operator int() converts the var to an integer (same as var::as_int()).  For other conversions, the methods var::as_bool(), var::as_int(), var::as_double(), var::as_string() and var::as_wstring() convert the var to an appropriate C++ type.  The conversion always succeeds, but may return a default value such as false, 0 or the empty string if the var doesn't contain an approproate type.  integers, doubles and strings try their best to convert their contents to the requested type.

Storing C++ values in var

The create() templated function returns a var containing the C++ value.  The templated method var::as() method accesses the stored value, or throws an exception ("not_supported") if the var does not store a value of the given type.

e.g. (cppvalues.cpp)

#include <cppscript>
#include <dynamic/extensions.hpp>
 
var script_main(var)
{
    var two = create(2);
    writeln( two.as<int>() ); // Output: 2
    writeln( two.as<std::string>() ); // Throws "not_supported"
    return 0;
}

Converting from C-style arrays

Arrays can be created from a C-style array, by passing them to the constructor of var.

var items[] = { 1, 2, 3.14, "pony" };
var a = items;

 

Arrays can be created from a pair of C++ iterators, using the array_it() function.

 

Lists can be created by passing a C-style array to the list() function, or by passing a pair of C++ iterators to the list_it() function.  E.g.

 

var items[] = { 1, 2, 3, "pony" };
var l2 = list(items);
var l4 = list_it(a, b); // a and b are input iterators

Sets can be created by passing a C-style array to the set() function, or by passing a pair of C++ iterators to the set_it() function.

Implementing native C++Script objects

This is beyond the scope of this tutorial - see the accompanying implementers guide.

.net integration

C++Script implements its own garbage collector rather than relying on the .net CLR.  Managed C++ can use both C++Script and the .net class libraries, though obviously this will not be portable.

There are a few little quirks with Visual C++, such as the fact that the program entry point can't be in a library, so add the file script_main.cpp to the project, and disable pre-compiled headers on the file if necessary.

Future versions of C++Script might support dynamic dispatch, and COM interoperability.

Unit Tests

The run_tests() function accepts an associative container (such as a map or an object), where each element in the container represents a different unit test.  All exceptions are caught and logged.  The function returns the number of tests which failed (0 means all tests passed).  The function assertx() throws an exception when its argument is false.  e.g. (test.cpp)

 
#include <cppscript>
 
void test_int_int_addition()
{
   assertx( var(1) + 2 == 3 );
}
 
void test_string_string_addition()
{
   assertx( var("abc") + "def" == "abcdef" );
}
 
void test_string_int_addition()
{
   assertx( var("abc") + 2 == "abc2" );
}
 
void test_int_string_addition()
{
   assertx( var(1) + "2" == 3 );
}
 
var script_main(var)
{
   var tests = map
          ("int int addition", test_int_int_addition)
          ("int string addition", test_int_string_addition)
          ("string int addition", test_string_int_addition)
          ("string string addition", test_string_string_addition);
   return run_tests( tests );
}