📜 ⬆️ ⬇️

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

ObjectScript is a new, open source object-oriented programming language. ObjectScript extends the capabilities of languages ​​such as JavaScript, Lua and PHP. His presentation was held on Habré some time ago in this article and aroused interest and heated discussion among readers. So I decided not to stop at the presentation and describe the ObjectScript API. I will try to make the article as short as possible, beating the API description into several parts.

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


The 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 instance of OS, work with it and correctly delete it, but not with the operator delete , but with the call of the release method.
')
OS instances can be created at the same time as many times as desired; if needed, 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 C ++ tools to simulate the following code on the OS:

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

What we have here is: a call to a global function 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 this for this function. If the function does not use this, well, for example, a static function, then null should be placed as this . We do it like this:

  os->getGlobal("print"); // #1 -     os->pushNull(); // #2 

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

  os->pushString("10 * (3+2) = "); // #3 -   

Now we 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 runOp method can perform mathematical, logical, and bitwise operators on values ​​in the stack using the OS kernel. In other words, if necessary, type conversions will occur, and so on ... OP_ADD performs an addition operator on two values ​​at the top of the stack (that is, what was placed on the stack the last two times). The result will replace them in the stack (that is, two values ​​will be removed from the stack, and the result added). OP_MUL - likewise for multiplication.

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

  os->call(2); //    2  

Everything, we look at the console ( print print the result to the console), it should be like this:

 10 * (3+2) = 50 

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

Example 2


Let's code 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 to the stack the object 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 setProperty method sets a property and removes the values ​​used from the stack (in this case, three values ​​are used at the top of the stack: object, property name and value).

Let's do the same thing 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 at the top of the stack is now the string "Bond" .

Now save our object to the global variable bar :

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

There are currently no values ​​in the stack. Now 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 do the 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


Let's code the following code on the OS:

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

Getting started 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 a result at output 1 (concat returns 1 result by default, if we request 0 results, then there will be no values ​​in the stack with results, if we request 2 or more values, then the first result will be from the concat function, and the rest will be added with nulls).

Now we 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 ObjectScript sources and an example from this article at this link , open proj.win32 \ examples.sln , project stack_usage .

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


All Articles