📜 ⬆️ ⬇️

ObjectScript API, integration with C ++. Part 3: Connecting a Module with C ++ Functions

ObjectScript is a new, open source object-oriented programming language. ObjectScript extends the capabilities of languages ​​such as JavaScript, Lua and PHP.

Part 3: Connecting a Module with C ++ Functions


Let's create our own module with functions that will be available in the code on the OS. Let's call the module my , it will contain two functions:


First, you need to write the functions of our future module in C ++, the first my_isdigit :
')
 static int my_isdigit(OS * os, int params, int, int, void*) { OS::String str = os->toString(-params); int len = str.getLen(); for(int i = 0; i < len; i++){ if(!isdigit(str[i])){ os->pushBool(false); return 1; } } os->pushBool(len > 0); return 1; } 

Small explanations on the bill:

 OS::String str = os->toString(-params); 

Here we get the first parameter as a string. params is the number of parameters that were passed to the function from the OS. -params is a relative pointer on the stack to the first parameter. If we needed to turn to the second parameter, then it would look like this: os->toString(-params+1) , to the third one - os->toString(-params+2) , etc.

The C ++ API provides a number of functions for getting different simple types from the stack: toFloat, toDouble, toInt, toString, toUserdata, popFloat , etc.

Sometimes a C ++ program does a lot of work with the stack. In this case, in order not to keep relative displacements in mind (since they will change when something is added or removed from the stack), it is convenient to work with an absolute pointer to the value in the stack, you can get it using getAbsoluteOffs(int offs) and then work like this:

 int params_offs = os->getAbsoluteOffs(-params); OS::String str = os->toString(params_offs); //   OS::String str = os->toString(params_offs+1); //  

It was a lyrical digression, now the second function of our module is my_hash :

 static int my_hash(OS * os, int params, int, int, void*) { OS::String str = os->toString(-params); int i, len = str.getLen(), hash = 5381; for(i = 0; i < len; i++){ hash = ((hash << 5) + hash) + str[i]; } hash &= 0x7fffffff; char buf[16]; for(i = 0; hash > 0; hash >>= 4){ buf[i++] = "0123456789abcdef"[hash & 0xf]; } buf[i] = 0; os->pushString(buf); return 1; } 

A little explanation on the bill:

  return 1; 

This is the number of values ​​returned by the function. The functions are ready, now we need to inform the OS that we have a new module with such functions:

 void initMyModule(OS * os) { OS::FuncDef funcs[] = { {"isdigit", my_isdigit}, {"hash", my_hash}, {} }; os->getModule("my"); os->setFuncs(funcs); os->pop(); } 

Now let's check how it works, let's write a program on OS (main.os), which for each value of the test array will call our functions in C ++:

 for(var i, s in ["123", "12w", 1234, " df", " "]){ print("my.isdigit("..s..") = "my.isdigit(s)" my.hash("..s..") = "my.hash(s)) } 

The program will display the following result:

 my.isdigit(123) = true my.hash(123) = bf9878b my.isdigit(12w) = false my.hash(12w) = f3a878b my.isdigit(1234) = true my.hash(1234) = f89c87c7 my.isdigit( df) = false my.hash( df) = f48478b my.isdigit( ) = false my.hash( ) = 5082f6c7 

Full text source code in C ++:

 #include "objectscript.h" #include <ctype.h> using namespace ObjectScript; static int my_isdigit(OS * os, int params, int, int, void*) { OS::String str = os->toString(-params); int len = str.getLen(); for(int i = 0; i < len; i++){ if(!isdigit(str[i])){ os->pushBool(false); return 1; } } os->pushBool(len > 0); return 1; } static int my_hash(OS * os, int params, int, int, void*) { OS::String str = os->toString(-params); int i, len = str.getLen(), hash = 5381; for(i = 0; i < len; i++){ hash = ((hash << 5) + hash) + str[i]; } char buf[16]; hash &= 0x7fffffff; for(i = 0; hash > 0; hash >>= 4){ buf[i++] = "0123456789abcdef"[hash & 0xf]; } buf[i] = 0; os->pushString(buf); return 1; } void initMyModule(OS * os) { OS::FuncDef funcs[] = { {"isdigit", my_isdigit}, {"hash", my_hash}, {} }; os->getModule("my"); os->setFuncs(funcs); os->pop(); } void main() { OS * os = OS::create(); initMyModule(os); os->require("main.os"); os->release(); } 


You can download the ObjectScript sources and an example from this article at this link , open proj.win32 \ examples.sln , project add_user_module .

Other relevant ObjectScript articles:


PS A small opus about OS::String


OS :: String is an object with an ObjectScript string that can be stored in custom C ++ code. Such a string retains a valid value throughout its existence. To get to point to a null-terminated string, you need to use the toChar() function. ObjectScript stores in memory all the different strings in a single copy , so OS::String is a constant string, it cannot be changed under any circumstances. But you can get a new line. OS::String implements a number of constructors and a concatenation operator, so OS::String can be created from custom code and work with it (if necessary).

Q: What happens if you execute os->release() earlier than OS::String strings stored in custom code are destroyed?

A: OS :: String captures an instance of OS, letting it know that it is used in external code. Therefore, os->release() does not destroy an instance of OS, but it will be destroyed when the last string OS::String ceases to exist.

Source: https://habr.com/ru/post/153021/


All Articles