Back to Home

AngelScript

Introduction In the process of reviewing LUA and Python · I highlighted that LUA is fast enough · but with a slightly unusual syntax. Python has a very simple syntax and mass ...

AngelScript

Introduction


In the process of reviewing LUA and Python, I highlighted that LUA is fast enough, but with a bit of an unusual syntax. Python has a very simple syntax and a lot of useful libraries, but, unfortunately, it turned out to be rather slow, and it is quite difficult to bind to C ++. And then at work they told me to use AngelScript, they say it’s convenient to bundle, faster than LUA and has a C-like syntax. As soon as I started to study it, I realized that this is the very scripting language of my dreams.

Preview


Here's what you can read about this language on Wikipedia:

AngelScript is an engine in which an application can register functions, properties, and types that can be used in scripts. Scripts are compiled into modules. The number of modules used varies depending on the needs. An application can also use different interfaces for each module using configuration groups. This is especially useful when an application works with several types of scripts, for example, GUI, AI, etc.

The "Hello, world" program in the simplest case looks like this:

voidmain(){ 
   print("Hello world\n"); 
}  


Yes, the syntax of the language pleases from the very beginning. The language supports both functional programming methods and OOP. From the very beginning, it captivates with its simplicity of registering functions, variables, types.

For example, registering a global variable:

g_Engine->RegisterGlobalProperty("int SomeVal",&SomeVal);  


where SomeVal is an int variable.

Registration of a global function:
g_Engine->RegisterGlobalFunction("void Print(string val)", 
                                 asFUNCTION(Print), asCALL_CDECL); 
voidPrint(string val){ 
   cout<<val.data(); 
}


Yes, AngelScript does not need to write binding functions, which is a huge plus compared to other languages. To register your types you have to write a couple of functions. A factory for creating instances and a reference counter, for the Type-reference type, and calls to the constructor and destructor, for an object of the Type-value type.

For example, we have a class float3 that we would like to register.

// класс счётчик ссылокclassRefC
{private:
     int refC;
public: 
     RefC(){refC=1;} 
     voidAddRef(){refC++;} 
     voidRelease(){ 
          if(!--refC) 
               deletethis; 
     } 
};
// Класс, который мы хотим зарегистрировать classfloat3:public RefC 
{
public:
     float x;
     float y;
     float z;
     float3(){x=y=z=0;}
     voidNormalize(){
          float Len=sqrt(x*x+y*y+z*z);
          Len=Len?Len:1;
          x/=Len;
          y/=Len;
          z/=Len;
     }
}
// Фабрикаfloat3* Float3FactoryE(){
    returnnew float3();
}
// Функция вывода на экранvoidPrintF3(float3* val){
    cout<<"x="<<val->x<<",y="<<val->y<<",z="<<val->z;
}


To do this, we register the object as a Type-link and indicate to it the factory, link counter, method and function of displaying data on the screen, and this is how it looks.

g_Engine->RegisterObjectType("float3",0,asOBJ_REF);
g_Engine->RegisterObjectMethod("float3"," void Normalize()",asMETHOD(float3, Normalize),asCALL_THISCALL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_FACTORY,"float3@ new_float3()",asFUNCTION(Float3FactoryE),asCALL_CDECL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_ADDREF,"void AddRef()",asMETHOD(float3,AddRef),asCALL_THISCALL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_RELEASE,"void Release()",asMETHOD(float3,Release),asCALL_THISCALL);
g_Engine->RegisterGlobalFunction("void Print(float3@ val)",asFUNCTION(PrintF3),asCALL_CDECL);


Of course, we won’t stop there, since we need access to the xyz values, so we must register them too, which we do by writing.
g_Engine->RegisterObjectProperty("float3","float x",offsetof(float3,x));
g_Engine->RegisterObjectProperty("float3","float y",offsetof(float3,y));
g_Engine->RegisterObjectProperty("float3","float z",offsetof(float3,z));


Everything is extremely simple and clear. Now in the script you can write
float3@ ObjPos;
ObjPos.x=1;
ObjPos.y=2;
ObjPos.z=3;
ObjPos.Normalize();
Print( ObjPos );


Having executed this script, we will see on the screen the value of the normalized vector.

Features



I was very pleased with the possibility of operator overloading in AngelScript. In C ++, for this, the operator keyword and operator symbol exist. AngelScript uses certain functions for this.

¦ - opNeg
¦ ~ opCom
¦ ++ opPreInc
¦ - opPreDec
¦ ++ opPostInc
¦ - opPostDec
¦ == opEquals
¦! = OpEquals
¦ <opCmp
¦ <= opCmp
¦> opCmp
¦> = opCmp
¦ = opAssign
¦ + = opAssign
¦ + = opAssign ¦ + = opAssign ¦ + = - = opSubAssign
¦ * = opMulAssign
¦ / = opDivAssign
¦ & = opAndAssign
¦ | = opOrAssign
¦ ^ = opXorAssign
¦% = opModAssign
¦ << = opShlAssign
¦ >> = opShrAssign
¦ >>> = opUShrAssign
¦ + opAdd opAdd_r
¦ - opSub opSub_r
¦ * opMul opMul_r
¦ / opDiv opDiv_r
¦% opMod opMod_r
¦ & opAnd opAnd_r
¦ | opOr opOr_r
¦ ^ opXor opXor_r
¦ << opShl opShl_r
¦ >> opShr opShr_r
¦ >>> opUShr opUShr_r
¦ [] opIndex

Suppose we want our vector to support adding another vector to itself, slightly modify our class for this.

classfloat3:public RefC 
{
public:
     float x;
     float y;
     float z;
     float3(){x=y=z=0;}
     voidNormalize(){
          float Len=sqrt(x*x+y*y+z*z);
          Len=Len?Len:1;
          x/=Len;
          y/=Len;
          z/=Len;
     }
     float3* operator+=(float3* _rval)
     {
          x+=_rval->x;
          y+=_rval->y;
          z+=_rval->z;
          this->AddRef();
          returnthis;
     } 
};

Only the registered new method remains.
g_Engine->RegisterObjectMethod("float3", "float3@ opAddAssign(float3@ _rval)",
                               asMETHOD(float3, operator+=), asCALL_THISCALL);


And now you can safely write like this:

float3@ ObjPos;
ObjPos.x=1;
ObjPos.y=2;
ObjPos.z=3;
float3@ ObjOffset;
ObjOffset .x=3;
ObjOffset .y=1;
ObjOffset .z=5;
ObjPos+=ObjOffset ; 
Print( ObjPos );  

and we will see on the screen x = 4, y = 3, z = 8.

AngelScript supports properties. It looks like this:
classMyObj 
{type get_ValueName();
     type set_ValueName(type Val);
}
MyObj a; 
type tmp=a.ValueName;// вызовется get_ValueName
a.ValueName = tmp; // вызовется set_ValueName 


Properties are also supported for the index operator:
classMyObj
{floatget_opIndex(int idx);
     voidset_opIndex(int idx, float value);
}
MyObj a;
float val=a[1];// вызовется get_opIndex 
a[2]=val;// вызовется set_opIndex 


useful links


Website developers www.angelcode.com
the SVN repository on the WIP angelscript.svn.sourceforge.net/svnroot/angelscript/trunk
Russian manual 13d-labs.com/angelscript_manual/main.html
manual in English www.angelcode.com/angelscript/sdk/ docs / manual / index.html
JIT Compiler github.com/BlindMindStudios/AngelScript-JIT-Compiler

Read Next