Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About Core::* types #59

Open
IngwiePhoenix opened this issue Sep 14, 2014 · 6 comments
Open

About Core::* types #59

IngwiePhoenix opened this issue Sep 14, 2014 · 6 comments

Comments

@IngwiePhoenix
Copy link
Contributor

I just had to do some reverse engeneering on the code, because I was very curios:

  1. How do I obtain "function pointers" from the script. As in: myFunc{value, function(){ ...callback... });
  2. How do I store a function away for later use?
  3. How can I obtain other types as permanent values?

Originally, I wondered about that with V8's C++ api in mind, where you have Local<...> and Persistant<...> types. The classes to fill into the template are either String, Number, Object, Function or any other valid JS type that is found under the v8 Namespace.

And secondarily, I wanted to learn more about the VM behind ObjectScript. Because - I wanted to know how data is saved and represented there. Boy I was not expecting what I found:

class Core {
    struct Value { ... }
    struct GCFunctionValue : public GCValue {...}
    struct GC{other type name}: public GCValue {...}
    class String { ... }
    class Buffer { ... }
}

As the class title suggested, those types were ment to be used internally. But - why?

As I asked in my previous questions, it would be highly usable to convert a type from the VM into something that C++ land understands. Turning something like this:

var callbackData = {
    beforeAction: function(){ ... },
    afterAction:  function(){ ... }
};

into something like this:

class OS::Value {
public:
    ...
    operator[](const OS_CHAR key);
    operator[](...);
    ...
    OS_EValueType type();
    void pushValue(OS*);
};

// In a function
OS::Value callbackData = os->getValue(...);
if(callbackData.isset("beforeAction")) {
    callbackData["beforeAction"]->pushValue(os);
    ...
    os->call(...);
}

For the case of embedding OS into a C++ application, it would make things very, very easy to be able to keep a refference to a function passed to a function and re-use it later. I have not come very far in my studdy yet, so I have to ask you for the implementation. But it could make things quite easy for embedding.

What is your opinion on this? Do you think it's do-able? Please let me know! I am kinda stuck with my previous issue at this moment...

@unitpoint
Copy link
Owner

You could obtain "function pointers" from the script using getValueId. BUT the function could be freed by OS garbage collector so you have to retain the function using retainValueById and release it (see releaseValueById) when you don't want to use the function.

You could put saved function to OS stack using pushValueById.

You could make value as permanent using retainValueById.

You could obtain other types as permanent values using the same way. Numbers, booleans and null are simple types. They have no id so you should save them as is (see toNumber, toFloat, toBool and so on).

The Core class is used internally. There are a lot of low end operations inside of the core. So programmer have to use the core carefully, it could be not simple. I was trying to implement general API functions inside of OS class so you should not use the core usually. You could use core's types and functions if you know what you do.

Feel free to ask me any questions.

@IngwiePhoenix
Copy link
Contributor Author

:) https://github.com/IngwiePhoenix/ObjectScriptValue
I'm on it. This shouldn't be too hard. I just started it, like, half a hour ago...

The idea is to mimic the life cycle of variables. So when the instance goes out of scope, the associated value does too. (see destructor).

I was wondering how I could make function calling easy, to support types. But first I need to get objects and such to work for real. I have only tested things using test.cpp so far. If you have any suggestions while I am at it, go ahead! I'll try to make it as compliant as possible, so it can be put into any OS projects.

@IngwiePhoenix
Copy link
Contributor Author

Im stuck at the getter. I know how to get Object properties with strings:

                case OS_VALUE_TYPE_OBJECT:
                    myOS->pushValueById(valueID);
                    myOS->getProperty(index);
                    char* str = (char*)(myOS->toString().toChar());
                    myOS->pop();
                    return str;

But how do I access array elements with a numeric index? I.e.: arr[2]

@unitpoint
Copy link
Owner

Awesome, you work very hard!

I've reviewed your OSValue.cpp, it seems like you need to upgrade OS version, there is no OS_VALUE_TYPE_UNKNOWN in ObjectScript at the moment. The latest version is ObjectScript 2.3.8-rc.

You could obtain a value from array as follows:

case OS_VALUE_TYPE_ARRAY:
    myOS->pushValueById(valueID);
    myOS->pushNumber(numIndex); // index of value
    /* Obtain string value from array... */
    myOS->getProperty();
    return myOS->popString();

The same way works for objects:

case OS_VALUE_TYPE_OBJECT:
case OS_VALUE_TYPE_USEDDATA:
case OS_VALUE_TYPE_USERPTR:
    myOS->pushValueById(valueID);
    myOS->pushString(strIndex); // string index of value
    // or myOS->pushNumber(numIndex); // number index of value
    myOS->getProperty();
    /* Obtain string value from object */
    return myOS->popString();
    // or obtain number value from object
    // return myOS->popNumber(); 

Note that OS's garbage collector frees unused values so you should retain (add a reference) value used by your own code or copy it. Be carefull using strings. You can use OS::String type as string value in your own code. OS::String retains string value already. Or copy string using std::string for example.

So your code is not safe

                char* str = (char*)(myOS->toString().toChar());
                myOS->pop();

change it to

                return myOS->popString();

or to

                return std::string((char*)(myOS->popString().toChar());

P.S.
OS_VALUE_TYPE_USEDDATA and OS_VALUE_TYPE_USEDPTR works like object but they created from C++ objects, for example DateTime is userdata really.

@IngwiePhoenix
Copy link
Contributor Author

Thanks! I will adapt that right in.

Yep, I work hard if I am focused on something. I am making this extension out of personal need for being able to store references to script functions later on.

In the constructor, I am already calling retainById in order to keep the object in cycle. On destruction, the value is freed accordingly.

My goal is to make an "almost complete" wrapper for the script types, so that its easier for C++ code to store them - like I need to store functions an dobjects; actually, the entire object contianing a function.

I was using a version of OS that I had downloaded at some point, will re-clone to have a properly updated header file. Thanks for the tipp. =)

@IngwiePhoenix
Copy link
Contributor Author

There goes. I now am going to implement numeric array access, accessing strings by number, etc. Shall be interesting! :)

After that, I think I can move on to setters. If an object has been declared (newObject, newArray), and then the Value instance was made, it should be able to also add values to the respective values. That is more like a little gimmick so I can later modify the object from within my code.

After that, I need to find a good way to implement calling functions, or just making a function to put the function into the stack...

But yeah, this little extension should be done soon! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants