YetAnotherForum
Welcome Guest Search | Active Topics | Log In | Register

free variables bound to native closures
cue
#1 Posted : Monday, January 3, 2011 11:23:01 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Hey! I might be missing something but there seems to be no way to get the number of free variables bound to a native closure. I need this to be able to tell which function parameters were passed in by the caller and which ones are actually free variables.
sq_getclosureinfo works only for squirrel closures, so something like sq_getfreevariablecount or sq_getnumfreevariables would be nice.
I can code in one myself, but I think this should make it into the official source, because it's really useful.


BTW: Why is sq_getfreevariable restricted to squirrel closures? Seems unnecessary to me.


BTW²: The docs have contradictions in some places. For instance, the API reference for sq_resetobject says that this function receives two parameters, the vm handle plus the pointer to the object handle, but it really only receives the pointer to the object handle.
Or another one: In the embedding tutorial the text clearly refers to an older implementation of sq_call, because it ignores the last parameter 'raiseerror' as it can be seen in the API reference for sq_call.
I know it's quite some work, but I think the docs should be reread and corrected, because the docs are the first place to go not only for experienced squirrel users, but also for newbies who fall for such mistakes, like I did. :)
gage
#2 Posted : Monday, January 3, 2011 11:41:59 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 11/4/2010(UTC)
Posts: 30

Thanks: 0 times
Was thanked: 1 time(s) in 1 post(s)
not sure how much this helps but in the code you wrote for the native closure I believe sq_top() will return the parameters for that method for you, if you know the free variable number ahead of time (I do) then you can determine how many parameters were passed in
cue
#3 Posted : Monday, January 3, 2011 11:58:23 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
I this case I do know the free variable number ahead of time, but I want to avoid having to hard-code the numbers in each function, since it's more work and would make the code unnecessarily prone to errors. A function like sq_getnumfreevariables would allow to write much more elegant and dynamic code.

Edit:

I just added sq_getfreevariablecount:

Code:

SQInteger sq_getfreevariablecount(HSQUIRRELVM v,SQInteger idx)
{
    SQObjectPtr &self=stack_get(v,idx);
    switch(type(self))
    {
    case OT_CLOSURE:
        return _closure(self)->_function->_noutervalues;
    case OT_NATIVECLOSURE:
        return _nativeclosure(self)->_outervalues.size();
    default:
        return -1;
    }
}


Now I can do the following for example :)

Code:

SQInteger my_func(HSQUIRRELVM vm)
{
    SQInteger optionalparam = somedefaultvalue;
    int numparams = sq_gettop() - sq_getfreevariablecount(vm, 0);
    if (numparams >= someval && sq_gettype(vm, someval) == OT_INTEGER) {
        sq_getinteger(vm, someval, &optionalparam);
    }
    // ...
}
gage
#4 Posted : Tuesday, January 4, 2011 4:25:59 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 11/4/2010(UTC)
Posts: 30

Thanks: 0 times
Was thanked: 1 time(s) in 1 post(s)
That may not be a bad idea, i didnt both with it because i have two native functions using free vars and my spec is pretty tight on them but all applications are different as they say :)
fagiano
#5 Posted : Tuesday, January 4, 2011 8:52:16 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
Hi, I'll see to add this function to squirrel 3.x before i do a stable realease.

ciao
Alberto
Follow me on Twitter @squirrellang
cue
#6 Posted : Tuesday, January 4, 2011 10:40:34 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Thanks Alberto!

What about making sq_getfreevariable also work for native closures?

Extending the current implementation would result in...
Code:

const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
{
    SQObjectPtr &self=stack_get(v,idx);
    const SQChar *name = NULL;
    switch(type(self))
    {
    case OT_CLOSURE:{
        SQClosure *clo = _closure(self);
        SQFunctionProto *fp = clo->_function;
        if(((SQUnsignedInteger)fp->_noutervalues) > nval) {
            v->Push(*(_outer(clo->_outervalues[nval])->_valptr));
            SQOuterVar &ov = fp->_outervalues[nval];
            name = _stringval(ov._name);
        }
                    }
        break;
    case OT_NATIVECLOSURE:
        if(_nativeclosure(self)->_outervalues.size()>nval){
            v->Push(_nativeclosure(self)->_outervalues[nval]);
            _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1);
        }
        break;
    default:
        break;
    }
    return name;
}

But here is the problem that error checking for native closures can't be done. Better would be to...
Code:

SQRESULT sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval, const SQChar** name)
{
    SQObjectPtr &self=stack_get(v,idx);
    switch(type(self))
    {
    case OT_CLOSURE:{
        SQClosure *clo = _closure(self);
        SQFunctionProto *fp = clo->_function;
        if(((SQUnsignedInteger)fp->_noutervalues) > nval) {
            v->Push(*(_outer(clo->_outervalues[nval])->_valptr));
            SQOuterVar &ov = fp->_outervalues[nval];
            if (name) {
                *name = _stringval(ov._name);
            }
        }
        else return sq_throwerror(v,_SC("invalid free var index"));
                    }
        break;
    case OT_NATIVECLOSURE:
        if(_nativeclosure(self)->_outervalues.size()>nval){
            v->Push(_nativeclosure(self)->_outervalues[nval]);
            if (name) {
                *name = NULL;
            }
        }
        else return sq_throwerror(v,_SC("invalid free var index"));
        break;
    default:
        return sq_aux_invalidtype(v,type(self));
    }
    return SQ_OK;
}

But changing the function signature of sq_getfreevariable will break any existing code that uses it currently. :/

However, if Squirrel 3.x is meant to break compatibility if needed, I think we should go with the second version. :)
fagiano
#7 Posted : Tuesday, January 4, 2011 11:51:27 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
That's possible as well. I'd rather not change the signature of the API if possible. We could just return "@NATIVE" as name for native outers and leave the api unchanged.

Alberto
Follow me on Twitter @squirrellang
cue
#8 Posted : Wednesday, January 5, 2011 1:08:39 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Sounds good to me! :)
fagiano
#9 Posted : Wednesday, January 5, 2011 1:55:38 AM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
BTW this code in your sample is not safe

int numparams = sq_gettop() - sq_getfreevariablecount(vm, 0);

you cannot rely on the fact that the current closure is at position 0 in the stack

Alberto
Follow me on Twitter @squirrellang
cue
#10 Posted : Wednesday, January 5, 2011 6:06:42 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Hm, can you explain why not? After discovering that the native closure is at position 0 in the stack it seemed logical to me that it holds at least for natives closures.

If I can't rely on that, is there a more reliable way to do what I did?
fagiano
#11 Posted : Thursday, January 6, 2011 12:39:33 AM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
closures in squirrel can be anyware in the stack usually 0 or below( < than 0), but you can't really know. If you want a function that access the current running closure you need to access the callstack (CallInfo).

Alberto
Follow me on Twitter @squirrellang
cue
#12 Posted : Friday, January 7, 2011 11:03:07 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Ah I see now, thanks for clearing up. Unfortunately at the moment there is no API to get the topmost closure from the call stack. Can we get sq_getcallee that pushes the closure of the topmost CallInfo in the call stack?
fagiano
#13 Posted : Friday, January 7, 2011 11:39:38 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
I think I'll implement a sq_getouterscount() or something similar, that gives you the number of outers of the current running closure.

Alberto
Follow me on Twitter @squirrellang
cue
#14 Posted : Saturday, January 8, 2011 2:04:11 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 1/3/2011(UTC)
Posts: 60
Man

Thanks: 0 times
Was thanked: 4 time(s) in 4 post(s)
Yeah, good idea. :)
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Clean Slate theme by Jaben Cargman (Tiny Gecko)
Powered by YAF 1.9.4 | YAF © 2003-2010, Yet Another Forum.NET
This page was generated in 0.226 seconds.