// Point.hpp // An extremely simple point class. class Point { public: Point() : _x(0), _y(0) { } Point(int x, int y) : _x(x), _y(y) { } int get_x() const { return _x; } int get_y() const { return _y; } void set_x(int x) { _x = x; } void set_y(int y) { _y = y; } void add_to_this(const Point& other) { _x += other._x; _y += other._y; } // A somewhat artificial overload; note the corresponding // eval header syntax. void add_to_this(int x, int y) { _x += x; _y += y; } private: int _x; int _y; friend Point add_points(Point& a, Point& b); }; inline Point add_points(Point& a, Point& b) { return Point(a._x + b._x, a._y + b._y); } // A somewhat artificial inheritance structure; note the corresponding // eval header syntax. class ThreeDimPoint : public Point { public: ThreeDimPoint(int x, int y, int z) : Point(x, y), _z(z) { } ThreeDimPoint() : Point(), _z(0) { } int get_z() const { return _z; } void set_z(int z) { _z = z; } private: int _z; };
// eval_example_header.ehpp // Defines the basic types (e.g. int, double, ...) #include "eval_headers/basic_types.ehpp" // These headers are nowhere near complete. #include "eval_headers/string.ehpp" #include "eval_headers/ostream.ehpp" EVAL_REGISTER_TYPE(Point) EVAL_REGISTER_CONSTRUCTOR(()) // default constructor EVAL_REGISTER_CONSTRUCTOR((int, int)) EVAL_REGISTER_CONSTRUCTOR((Point)) // copy constructor EVAL_REGISTER_METHOD(get_x) EVAL_REGISTER_METHOD(get_y) EVAL_REGISTER_METHOD(set_x) EVAL_REGISTER_METHOD(set_y) EVAL_REGISTER_METHOD_OVERLOADED(void, (const Point&), add_to_this) EVAL_REGISTER_METHOD_OVERLOADED(void, (int, int), add_to_this) EVAL_END_TYPE EVAL_REGISTER_FUNCTION(add_points) EVAL_REGISTER_TYPE(ThreeDimPoint) // Note: EVAL_INHERIT_FROM semantically really means "implements". // Inheritance hierarchy is irrelevant; however, this class must // implement/inherit all the methods (excluding constructors) in Point, or // compilation will fail (in C++ it is possible to create a subclass which // does not implemented all the methods of its superclass exactly). // If this class overwrites methods from the base class, you can list // them explicitly, but that's not necessary. EVAL_INHERIT_FROM(Point) EVAL_REGISTER_CONSTRUCTOR(()) EVAL_REGISTER_CONSTRUCTOR((int, int, int)) EVAL_REGISTER_CONSTRUCTOR((ThreeDimPoint)) EVAL_REGISTER_METHOD(get_z) EVAL_REGISTER_METHOD(set_z) EVAL_END_TYPE // Note that it is possible to register functions/methods/types // with a different name than in their C++ source (so that the // scripts would be able to refer to an alias name).
// eval_example_script.epp // std::cout, point1 and point2 come in as arguments // call operator<< function std::cout << "Hello world from an eval script" << "\n"; val point3; // Declare new variable (accessible from calling program). // All variables have type val; declarations go on their own line. point3 = Point(point1.get_x(), point2.get_y()); // modify an argument passed in point2.add_to_this(point3); point2.add_to_this(1, 2); val point_rv; point_rv = add_points(point1, ThreeDimPoint(8, 9, 6)); // adding in 2D only! // Note: val temp; temp = 3; // const int temp = int(3); // int
// eval_example.cpp #include <string> #include <iostream> #include <assert.h> // The eval header defines 2 functions, eval_file and eval (takes const char *) #include "eval.hpp" // The val class is a generic class for wrapping arbitary instances/primitives. #include "val.hpp" // A plain old c++ class, serving as an example. #include "Point.hpp" // The EVAL_INCLUDE_FILE1 is the eval header that determines which // functions/methods/constructors the scripts have access to. #define EVAL_INCLUDE_FILE1 "eval_example_header.ehpp" // Some preprocessor magic happens at this point. Suffices to say that // you now have a class deriving from eval::execution_context, called // MyExecContext. This custom excecution context knows about // functions/methods/constructors as per EVAL_INCLUDE_FILE1. // (You can create more than 1 execution context.) #define EVAL_EXECUTION_CONTEXT_NAME MyExecContext #include "create_execution_context_definition.hpp" int main() { MyExecContext e; // Create our custom execution context. e.register_all(); // Register all functions/methods/constructors. In some // circumstances, the execution context can be used // without this call. // Make std::cout available to the script (in future library versions, // this may be done in the appropriate eval standard header). e["std::cout"] = eval::val(&std::cout, eval::UNMANAGED_PTR); // make some Points available to the script e["point1"] = eval::val(new Point(4, 5), eval::TRANSFER_OWNERSHIP); Point point2(6, 7); e["point2"] = eval::val(&point2, eval::UNMANAGED_PTR); // execute our example script (the script is in the same directory; // specifying a more complete path just helps the automated testing system) eval_file(e, "../examples/eval_example_script.epp"); // We have access to variables defined in the script. Point *point_rv = e.extended_val_cast_ptr<Point>(e["point_rv"]); assert(point_rv->get_x() == 12); assert(point_rv->get_y() == 14); // The script also modified existing objects (arguments) assert(point2.get_x() == 11); assert(point2.get_y() == 16); // Note that various casting methods exist, allowing you to attempt // to convert return values to a particular type (or just get a string // or int representation, if possible). return 0; }