ObjectScript API, integration with C ++. Part 1: working with the stack, calling OS functions from C ++

  • Tutorial
ObjectScript is a new open source object-oriented programming language. ObjectScript extends the capabilities of languages ​​such as JavaScript, Lua, and PHP. His presentation took place on a hub some time ago in this article and aroused interest and heated discussion among readers. Therefore, I decided not to dwell on the presentation and describe the ObjectScript API. I will try to make articles as short as possible by breaking the API description into several parts.

Part 1: working with the stack, calling OS functions from C ++


A minimal program using OS (ObjectScript) is as follows:

#include "objectscript.h"
using namespace ObjectScript;
int main()
{
    OS * os = OS::create();
    // TODO: main code here
    os->release();
    return 0;
}

Those. create an OS instance, work with it and delete it correctly, but not with the help of an operator delete, but with a method call release.

OS instances can be created simultaneously as many as desired, if necessary, they will work completely independently of each other.

Next, I will give an example of code that should be located instead of TODO: main code here .

So, let's use the C ++ tools to simulate the following OS code:

print("10 * (3+2) = ", 10 * (3+2))

What we have here: a global function call with two parameters, the first is a constant string, the second is the result of mathematical operations.

The first thing to do is prepare a function call. To do this, you need to put two values ​​on the stack, the first is the function itself, the second is thisfor this function. If the function does not use this, well, for example, a static function, then thisyou need to put it in quality null. We do it like this:

    os->getGlobal("print");    // #1 - количество значений в стеке
    os->pushNull();            // #2

Now we add to the stack the parameters with which the function will be called:

    os->pushString("10 * (3+2) = "); // #3 - первый параметр

Now simulate the mathematical operations for the second parameter:

    os->pushNumber(10);       // #4
    os->pushNumber(3);        // #5
    os->pushNumber(2);        // #6
    os->runOp(OP_ADD);        // #5 - 3+2
    os->runOp(OP_MUL);        // #4 - 10 * (3+2)

Done! the method runOpcan perform mathematical, logical and bitwise operators on values ​​in the stack using the OS kernel tools. In other words, if necessary, type conversions will happen, etc. ... it OP_ADDperforms the addition operator on two values ​​at the top of the stack (i.e. what was placed on the stack the last two times). In this case, the result will replace them on the stack (i.e., two values ​​will be removed from the stack, and the result will be added). OP_MUL- similarly for multiplication.

At the moment, we will have 4 values ​​on the stack: 1 - function, 2 - null, 3 - string, 4 - number. Excellent! you can call:

    os->call(2); // вызвать функцию с 2 параметрами

That's it, we look at the console ( printoutput the result to the console), it should be like this:

10 * (3+2) = 50

In this case, the stack will be completely empty, because 4 values ​​used when calling the function will be removed from the stack.

Example 2


We simulate the following code on the OS:

bar = {firsname="James", lastname="Bond"}
bar.profession = "actor"
print bar

Create a new object on the stack:

os->newObject();            // #1

Set the first property firsname="James":

os->pushStackValue(-1);     // #2

-1 is a relative pointer to the top of the stack, i.e. add an object to the stack for which we will set the property (the object is added to the stack by reference).

os->pushString("firsname"); // #3 - имя свойства
os->pushString("James");    // #4 - будущее значение свойста
os->setProperty();          // #1

The method setPropertysets the property and takes the used values ​​from the stack (in this case, three values ​​are used on the top of the stack: object, property name and value).

We will do the same with the second property, but in a shorter way:

os->pushString("Bond");              // #2 - значение
os->setProperty(-2, "lastname");     // #1

-2 is a relative pointer to the second value from the top of the stack (this is our object), and now there is a line at the top of the stack "Bond".

Now save our object to the global variable bar :

os->setGlobal("bar");       // #0

There are currently no values ​​in the stack. Now we execute the code bar.profession = "actor":

os->getGlobal("bar");       // #1 - помещаем в стек значение переменной bar
os->pushString("actor");    // #2
os->setProperty(-2, "profession"); // #1
os->pop();                  // #0 - убераем значение переменной bar из стека

Done, now we do print bar:

os->getGlobal("print");     // #1
os->pushNull();             // #2
os->getGlobal("bar");       // #3
os->call(1);                // #0

and look at the console, it should be like this:

{"firsname":"James","lastname":"Bond","profession":"actor"}

Example 3


We simulate the following code on the OS:

print(concat(5, " big differences"))

We start as usual:

os->getGlobal("print");     // #1 - добавляем в стек глобальную функцию print
os->pushNull();             // #2 - добавляем this для функции print
os->getGlobal("concat");    // #3 - добавляем в стек глобальную функцию concat
os->pushNull();             // #4 - добавляем this для функции concat
os->pushNumber(5);          // #5 - первый параметр для concat
os->pushString(" big differences"); // #6 - второй параметр для concat
os->call(2, 1);             // #3 - вызываем функцию concat

At this stage, we called a function with 2 parameters and requested 1 result at the output (concat returns 1 default result, if we request 0 results, then after the function call there will be no values ​​in the stack with results, if we require 2 or more values, then the first result will be from the concat function, and the rest will be complemented by nulls).

Now call print:

os->call(1); // #0

in the console should be like this:

5 big differences

Full text of the program:

#include "objectscript.h"
using namespace ObjectScript;
int main()
{
    OS * os = OS::create();
	/*
		print("10 * (3+2) = ", 10 * (3+2))
	*/
    os->getGlobal("print");    // #1 - stack values, it's print function from standart library
    os->pushNull();            // #2 - null, it's function this, each call of function must have this
    // push the first argument
    os->pushString("10 * (3+2) = "); // #3 - we have 3 stack values here
    // prepare second argument
    os->pushNumber(10);       // #4
    os->pushNumber(3);        // #5
    os->pushNumber(2);        // #6
    os->runOp(OP_ADD);        // #5 - 3+2
    os->runOp(OP_MUL);        // #4 - 10 * (3+2)
    os->call(2); // call function with 2 arguments
    /*
        bar = {firsname="James", lastname="Bond"}
        bar.profession = "actor"
        print bar
    */
    os->newObject();            // #1 - new object
    os->pushStackValue(-1);     // #2 - the same object, -1 - is relative pointer to the top stack value
    os->pushString("firsname"); // #3 - property key
    os->pushString("James");    // #4 - property value
    os->setProperty();          // #1 - setProperty uses 3 stack values and pop them
    // second way of same functionality
    os->pushString("Bond");     // #2 - property value
    os->setProperty(-2, "lastname"); // #1
    os->setGlobal("bar");       // #0 - assign object value to global bar variable, pop value
    // let's do bar.profession = "actor"
    os->getGlobal("bar");       // #1 - our global a variable
    os->pushString("actor");    // #2 - property value
    os->setProperty(-2, "profession"); // #1
	os->pop();                  // #0
    // let's do print bar
    os->getGlobal("print");     // #1
    os->pushNull();             // #2
    os->getGlobal("bar");       // #3
    os->call(1);                // #0
    /*
        print(concat(5, " big differences"))
    */
    os->getGlobal("print");     // #1 - print function
    os->pushNull();             // #2 - this for print
    os->getGlobal("concat");    // #3 - concat function
    os->pushNull();             // #4 - this for concat
    os->pushNumber(5);          // #5
    os->pushString(" big differences"); // #6
    os->call(2, 1);             // #3 - result is already at the top of stack
    os->call(1);                // #0
    os->release();
    return 0;
}

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

Also popular now: