ObjectScript API, integration with C ++. Part 3: connecting a module with functions in C ++

  • Tutorial
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 functions in C ++


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

  • isdigit will check if the string passed in the parameter consists of numbers only
  • hash will convert the parameter to a hash string according to our algorithm

To begin with, you need to write the functions of our future module in C ++, the first one 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;
}

A little explanation on the bill:

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

Here we get the first parameter as a string. params- this is the number of parameters that were passed to the function from the OS. -paramsIs the relative pointer in 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 - os->toString(-params+2)and so on.

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

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

int params_offs = os->getAbsoluteOffs(-params);
OS::String str = os->toString(params_offs); // перпый параметр
OS::String str = os->toString(params_offs+1); // второй

This was a 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 small 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 the following 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, 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 output 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 source code in C ++:

#include "objectscript.h"
#include 
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 source code and an example from this article at this link , open proj.win32 \ examples.sln , the add_user_module project .

Other relevant articles about ObjectScript:


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 all the time of its existence. To get to point to a null-terminated string, you need to use a function toChar(). ObjectScript stores in memory all different lines in a single copy , therefore it OS::Stringis a constant line, it cannot be changed under any circumstances. But you can get a new line. OS::Stringimplements a number of designers and the concatenation operator, so it OS::Stringis quite possible to create from user code and work with it (if necessary).

Q: What will happen if you execute os->release()before the lines OS::Stringstored in the user code are destroyed ?

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

Also popular now: