Simple Script engine for C++


General overview

ZetScript is a programming language and comes with and API that allows bind your C++ code into script side.

A Hello World sample is shown below,

#include "CZetScript.h"

using namespace zetscript;

void say_helloworld(){
	printf("Hello World!");
}

int main(){

	CZetScript *zs = CZetScript::getInstance(); // instance zetscript

	register_C_Function("say_helloworld",say_helloworld); // register C function say_helloworld

	zs->eval("say_helloworld();"); // Call c function and prints hello world!
	return 0;
}


Zetscript includes the following features:

  • Virtual Machine
  • Language syntax close to Javascript
  • MSVC++ 32/64 bits MSVC 2015/2017 or build tools v141
  • Linux/MinGW 32/64 bits, gnu compiler 4.8 or above
  • Save/Load state support
  • Dynamic Garbage collector
  • Straightforward way to bind C++ variables, functions and classes
  • The library size is ~1Mb on gnu toolchain and ~400KB on MSVC++
  • Override operators through metamethods



Language overview

Built-in types

Zetscript has a built in basic types like integers, numbers, booleans and containers as vectors and structures

var i=10; //integer
var f=0.5; // number
var s="a string"; // string
var b=true; // boolean

var vector=[1,0.5, "a string", true]; // vector

var struct={ // structure
	i: 10,
	f: 0.5,
	s: "a string",
	b: true,
	v: [1,0.5, "a string", true]
};
 

Scope

Zetscript has an easy concept of global scope declaring variables in the top of evaluating scope. Local variables are within blocks like function or loops. Local vars are destroyed when it exits from block, unless is not referenced by other variable

var global_var = 0; // global var (never is destroyed when is declared)

{ // starting block: declaring local variables starts here. 
  // You can access also to global var.

	var local_var = 2; // local var 
	// ...

} // ending block: local_var is destroyed

Conditionals

Zetscript supports if-else and switch conditionals

// if-else conditional
if(number < 10){
	print("number less than 10");
}else{
	print("number greater equal than 10");
}

// switch conditional
switch(number){
case 0:
case 1: 
	print("number is 0 or 1");
	break;
case 2:
	print("number is 2");
	break;
default:
	print("number is : "+number);
	break;
}

Loops

Zetscript supports while,do-while and for as loops iterators

var i=0;
// while loop
while(i < 10){
	print("i:"+i);
	i++;
}

// do-while loop
do{
	print("i:"+i);
	i++;
}while(i < 20);

// for loop
for(var j=0; j < 10; j++){
	print("j:"+i);
}


Classes and inheritance

Zetscript supports class and inheritance. Function and variables members are referenced through this keyword. Also it can define variables/functions later. Inheritance support super() function in order to call parent function. To instance class is done through new operator

// A class example
class Test{
	var data1;
	
	function function1(a){
		this.data1 =a;
		print("calling from Test. Data1:"+this.data1);
	}
};

// include member variable data2
var Test::data2; 

// include member function function2
function Test::function2(){ 
	this.data2="a string";
}

// A inheritance class example. 
// TestExtended inherites data1,data2,function1 and function2. 
class TestExtended: Test{
	var data3;
	function function1(a){
		super(2); // it calls Test::function1(2)
		this.data1+=5; // Now data1=5+2 = 7
		print("calling from TestExtended. Data1:"+this.data1);
	}
	
	function function3(){ // 
		this.data3=6;
		print("data3 is "+this.data3);
	}
};

var t=new TestExtended(); // instances TestExtended class


The API

Bind a variable

Zetscrip can bind variables to operate in script sides.

#include "CZetScript.h"

using namespace zetscript;

int main(){

	string	string_var = "in c++";

	CZetScript *zs = CZetScript::getInstance(); // instance zetscript

	register_C_Variable("string_var",string_var); // it registers c++ string_var as variable string_var in script

	zs->eval(
		"string_var+=\" and in script\";" // concatenates " and in script"
		"print(\"string_var:\"+string_var);" // prints "string_var:in c++ and in script"
	);
	return 0;
}

Bind a class and its members

Binding C++ class in Zetscript is done easily with register_C_Class method. To bind variable and functions members it can be done through register_C_VariableMember and register_C_FunctionMember methods respectively. In script side you can instance the registered class through operator new. When the instanced C Class variable is not used the user has to delete it with operator delete

#include "CZetScript.h"

using namespace zetscript;

class MyClass{
public:
	int data1;

	void function1(int arg){
		this->data1 = arg;
		printf("Int argument is %i\n",this->data1);
	}
};

class MyClassExtend:public MyClass{
public:
	float data2;

	void function2(float * arg){
		this->data2 = *arg;
		printf("Float argument is %.02f\n",this->data2);
	}
};

int main(){

	CZetScript *zs = CZetScript::getInstance(); // instance zetscript
	
	register_C_Class<MyClass>("MyClass"); // register MyClass with name MyClass in script side.
	register_C_Class<MyClassExtend>("MyClassExtend"); // register MyClassExtend with name MyClassExtend in script side.
	
	class_C_baseof<MyClassExtend,MyClass>(); // tell that MyClassExtend is base of MyClass

	register_C_VariableMember<MyClassExtend>("data1",&MyClass::data1); // register data1 named data1 in script side as variable member.
	register_C_FunctionMember<MyClassExtend>("function1",&MyClass::function1); // register function1 named function1 in script side as function member.

	register_C_VariableMember<MyClassExtend>("data2",&MyClassExtend::data2); // register data2 named data1 in script side as variable member.
	register_C_FunctionMember<MyClassExtend>("function2",&MyClassExtend::function2); // register function2 named function2 in script side as function member.



	zs->eval(
		"var myclass = new MyClassExtend();" // instances MyClassExtend
		"myclass.function1(12);" // it prints "Int argument is 12"
		"myclass.function2(0.5);" // it prints "Float argument is 0.5"
		"print(\"data1:\"+myclass.data1);" // it prints "data1:12"
		"print(\"data2:\"+myclass.data2);" // it prints "data2:0.5"
		"delete myclass;" // delete script var with c pointers attached inside.
	);

	return 0;
}


Call script function from c++

Once you have evaluated the script you can call function script from c++ until up 6 parameters. Call script function from c++ is done through the function CZetScript::bind_function. Just pass the function name with function type as template parameter and it creates an std::function that embeds function information. Also it is possible to link/call function member from object instanced on global scope.

	
#include "CZetScript.h"

using namespace zetscript;

int main(){

	CZetScript *zs = CZetScript::getInstance(); // instance zetscript

	zs->eval(
		"class Test{"
		"	var data1;"
		"	function function1(arg){"
		"		print(\"calling Test.Function:\"+arg);"
		"	}"
		"};"
		""
		"function delete_test(){"
		"	delete test;"
		"	print(\"test variable was deleted\");"
		"}"
		""
		"var test=new Test();"
	);

	
	std::function<void()>  * delete_test=bind_function<void ()>("delete_test"); // instance function delete_test function.
	std::function<void(int)> * test_function1=bind_function<void (int)>("test.function1"); // instance member function test.function1.
	
	(*test_function1)(10); // it calls "test.function" member function with 10 as parameter.
	(*delete_test)(); // it calls "delete_test" function with no parameters

	// delete functions when they are used anymore
	delete 	test_function1;
	delete 	delete_test;

}