Table of Contents

Including In Your Project

Ensure that "<sqrat root>/include" is in your include path and include "sqrat.h" Yup, that's all there is to it!

Basic Usage

The core of Sqrat revolves around it's ability to bind C++ classes, functions, and variables. All binding is done on either a Table or Class, and looks like this:

	void myFunc() { }

	class MyClass {
	public:
		void Foo() {}
		int bar;
	};

	void BindSquirrel(HSQUIRRELVM vm) {
		using namespace Sqrat;

		Table myTable(vm);
		myTable.Func("MyFunc", &myFunc);
		
		Class<MyClass> myClass(vm);
		myClass.Func("Foo", &MyClass::Foo);
		myClass.Var("bar", &MyClass::bar);
		
		RootTable(vm).Bind("MyTable", myTable);
		RootTable(vm).Bind("MyClass", myClass);
	}
	

After running the above code you will then have access to both MyTable and MyClass in Squirrel, accessed via the root table like so:

	MyTable.MyFunc();

	instance <- MyClass();
	instance.Foo();
	instance.bar = 1;
	

A couple of things to notice: Niether the Table or Class were assigned names when they were created. They were only associated with a name when bound to their parent table (root). This closely models Squirrel's slot system and allows for greater flexibility when binding, not to mention more uniformity of the interface.

Also, notice that we need to explicitly define which table the objects are binding to, root is never implied. Doing so allows nesting of table definitions like so:

	RootTable(vm).Bind("MyTable", myTable);
	myTable.Bind("MyClass", myClass);
	

Which would then be accessed in Squirrel as such (and can be used to emulate namespaces):

	instance <- MyTable.MyClass();
	

Aside from the basic syntax shown above there are a couple of alternative syntaxes for defining bindings that can reduce the amount of redundant typing needed and make the code easier to read. First off, all variable and function definitions can be chained together like so (Whitespace is irrelevant):

	myClass
		.Func("Foo", &MyClass::Foo)
		.Var("bar", &MyClass::Bar)
		;
	

Definitions like this can also be inlined inside Bind calls:

	RootTable(vm).Bind("MyClass", Class<MyClass>(vm)
		.Func("Foo", &MyClass::Foo)
		.Var("bar", &MyClass::Bar)
	);
	

The only function that cannot be chained is Bind itself, due to static order of initialization issues. Altogether this means that the first binding sample could also be declared like such with no change in functionality:

	void BindSquirrel(HSQUIRRELVM vm) {
		using namespace Sqrat;
		
		RootTable(vm).Bind("MyTable", Table(vm)
			.Func("MyFunc", &myFunc)
		);
		
		RootTable(vm).Bind("MyClass", Class<MyClass>(vm)
			.Func("Foo", &MyClass::Foo)
			.Var("bar", &MyClass::Bar)
		);
	}
	

In addition, if you don't need to differentiate between multiple virtual machines you can cut down on some code by specifying a Default VM:

	void BindSquirrel(HSQUIRRELVM vm) {
		using namespace Sqrat;
		
		DefaultVM::Set(vm);
		
		RootTable().Bind("MyTable", Table()
			.Func("MyFunc", &myFunc)
		);
		
		RootTable().Bind("MyClass", Class<MyClass>()
			.Func("Foo", &MyClass::Foo)
			.Var("bar", &MyClass::Bar)
		);
	}
	

The default vm takes effect globally once set, and can be retrieved at any time using Sqrat::DefaultVM::Get()

Scripts

Sqrat provides helper objects for the loading, compiling, and running of scripts either from a string or a file. In addition, compiled scripts can be written out to a file for faster loading later on.

To compile and run a script, use the following code:

	try {
		Script script1, script2;
		
		script1.CompileString("::print(\"Hello World\");");
		script2.CompileFile("/Path/to/Script.nut");
		
		script1.Run();
		script2.Run();
	} catch( Exception ) {
		// Handle exceptions here
	}
	

Note that if either the compile or run fails they will throw a Sqrat::Exception. Calling Message() on the exception will give details about the failure.

Objects

The Sqrat Object is the base class for both the Table and Class. It is essentially a smart pointer wrapper for HSQOBJECTs. The HSQOBJECT has a reference added any time a Sqrat Object is created or copied and is dereferenced upon deletion.

If the object represents a Table or Class you may also retrieve the values of a given slot using GetSlot. This will return another Sqrat Object:

	Object slotVal = myObject.GetSlot("myVal");
	

If the object represents a value you can retreive that value by calling Cast with the appropriate type:

	int objVal = myObject.Cast<int>();
	

This also works for class instances:

	MyClass* mc = myObject.Cast<MyClass*>();
	

You can test if an Object points to a NULL value using IsNull(). Putting these methods together gives you a consistent way of accessing Squirrel variables:

	// Get the int value of myVar from the root table
	Object myIntObj = RootTable().GetSlot("myInt");
	if(!myIntObj.IsNull()) {
		int myInt = myIntObj.Cast<int>();
	}
	

Tables

The Sqrat Table is an Object that can have functions or values bound to it. Functions are bound by calling Func:

	myTable.Func("MyFunc", &myFunc);
	

In this case &myFunc is a reference to a global or static function. If there are multiple overloads for myFunc, Sqrat needs to know which to use. These cases can be disambiguated by providing the function signature as a template type to Func:

	myTable.Func<bool (*)(int, float)>("MyFunc", &myFunc);
	

If you want to bind multiple function to the same name, the Overload function is used:

	myTable.Overload<bool (*)(int)>("MyFunc", &myFunc);
	myTable.Overload<bool (*)(int, float)>("MyFunc", &myFunc);
	

When overloading a function, each overload must have a different number of parameters. Also be aware that there is some additional overhead when using Overload instead of Func, as the call must be disambiguated at runtime.

Raw Squirrel functions can also be bound to a table using SquirrelFunc, which is called exactly like Func:

	myTable.SquirrelFunc("MySqFunc", &mySqFunc);
	

The function passed to SquirrelFunc must be a SQFUNCTION, which is defined like so:

	SQInteger mySqFunc(HSQUIRRELVM vm) {}
	

When using a Squirrel Function you are responsible for all stack management.

Classes

Sqrat Classes are used very much like tables, but can have instances created of them from within Squirrel. Function binding is identical to tables, but are now passed references to member functions instead:

	myClass.Func("MyFunc", &MyClass::MyFunc);
	

Class functions are disambiguated the same way as table functions, and can also be overloaded like table functions using the Overload function. In addition to member functions, you can also bind a global or static function as a member function using GlobalFunc, which has syntax identical to Func:

	myClass.GlobalFunc("MyFunc", &myGlobalFunc);
	

When binding a function using GlobalFunc, the first argument of the bound function must be a pointer to the class type that the function is being bound to, which will be set to the calling instance when the function is invoked.

Static functions can also be bound in the same way using StaticFunc, but static functions will not be passed the calling instance:

	myClass.StaticFunc("MyStaticFunc", &MyClass::myStaticFunc)
	myClass.StaticFunc("MyStaticFunc2", &globalStaticFunc)
	

Static functions do not need to be called on an instance within Squirrel (although they can be), you can call them directly on the class:

	MyClass.MyStaticFunc();
	

Variables are treated simliarly to Functions. Instance variables are bound with Var:

	myClass.Var("MyInt", &MyClass::MyInt);
	

And static variables are bound with StaticVar:

	myClass.StaticVar("MyStaticInt", &MyClass::MyStaticInt);
	

Sqrat also allows you to expose Properties to Squirrel via the Prop method. A property is a variable that is accessed via a getter and setter function natively, but appears to Squirrel as a standard variable. For example, if you had a class defined like so:

	class MyClass {
	public:
		int GetMyVar() { return myVar; }
		void SetMyVar(int i) { myVar = i; }
		
	private:
		int myVar;
	};
	

you can bind the Get and Set methods as a property rather than as separate functions.

	myClass.Prop("MyVar", &MyClass::GetMyVar, &MyClass::SetMyVar);
	

Accessing the variable in Squirrel then works like any other variable:

	mc <- MyClass();
	mc.MyVar = 5;
	

If you wish, you can make the property read only by only supplying a Get function

	myClass.Prop("MyVar", &MyClass::GetMyVar);
	

Constants and Enumerations

Constants and enumerations are both handled similarly by Squirrel in that both are evaluated at compile time (like C++ defines). This can improve the performance of scripts by skipping the table lookups normally associated with variable use.

Constant binding happens on the ConstTable object, which functions in a very similar manner to the RootTable object. It is limited to two operations, however: Const and Enum. Const will set one of the valid constant values (int, float, or string) to the given name:

	ConstTable(vm)
		.Const("ConstInt", 12)
		.Const("ConstFloat", 3.14)
		.Const("ConstString", "Hello World!")
		;
	

These are accessed from the script as global variables:

	::print(ConstString); // prints "Hello World!"
	local x = ConstInt - 4; // x = 8;
	

Enumerations are simply named groups of constant values. Creation of an enumeration is done with the Enumeration object and bound to the ConstTable with Enum.

	Enumeration color(vm);
	color.Const("Red", 1);
	color.Const("Green", 2);
	color.Const("Blue", 3);
	
	ConstTable(vm).Enum("Color", color);
	

Or, of course:

	ConstTable(vm).Enum("Color", Enumeration(vm)
		.Const("Red", 1)
		.Const("Green", 2)
		.Const("Blue", 3)
	);
	

Enumerations are accessed from script like static class members:

	::print(Color.Red); // prints "1"
	

Functions

Functions from Squirrel can be queried and called from C++ or even be passed to C++ as an argument using the Sqrat::Function object. There are two ways to retrieve a squirrel function:

	Function funcA(RootTable(vm), "FunctionName"); // Via the constructor
	Function funcB = RootTable().GetFunction("FunctionName"); // Via the class or table
	

As with objects, IsNull will indicate if the function retreived is valid

	if(funcA.IsNull()) { /* function not retreived. handle appropriately */ }
	

Once retrieved, a function can be called using either the Evaluate or Execute function. Both will call the squirrel function, while Evaluate will return the result of the call (if there is one). Both can be called with up to 9 arguments.

	int result = funcA.Evaluate<int>(1, "String");
	funcA.Execute(2, "Bob");
	funcA(3, "Hello!"); // Same as Execute
	

A function can also be passed to you from Squirrel (like a callback)

	// Squirrel Code
	function Add(a, b) { return a + b; }
	d = ::NativeFunc(1, 2, Add); // d should equal 3

	// C++ Code
	int NativeFunc(int a, int b, Function op) {
		return op.Evaluate<int>(a, b);
	}
	

Please note that Sqrat has no way of determining if the number or type of arguments you pass to the function call match what Squirrel is expecting. It is up to the developer to ensure that calls from C++ match their squirrel counterparts.

Limitations

Calling sq_suspendvm()

Due to the design of the Squirrel API sq_suspendvm(), calling it from a C++ function which is in turn called by Squirrel code will not suspend the VM successfully; you can suspend a given VM by calling ::suspend() from Squirrel code. (note from SourceForge Bug 3507590)

Constructors with multiple arguments

Current Sqrat does not support binding C++ constructors with one or more arguments. This is to be addressed in future versions. (note from SourceForge Bug 3514004)