albertodemichelis / squirrel

Official repository for the programming language Squirrel
http://www.squirrel-lang.org
MIT License
911 stars 155 forks source link

Function Reference Parameters (Extending the 'outer' system) #293

Open Peach1 opened 5 days ago

Peach1 commented 5 days ago

So Squirrel language already has 'outers' which act like references:

local x = 0; function mod() { x = 5; } mod(); print(x) // x is now 5

Squirrel "Outers" are almost references, but Squirrel's outers are limited to local variables in the _parent function.

So, with some modification of Squirrel's outer system, how can we implement this feature:

function mod(&x) { x = 5; }  local x = 0; mod(x); print(x);

For Syntax: Parsing & in CreateFunction would need to call something like MarkLocalAsOuter() for each & reference parameter

Then for runtime

Possibly take this code fromSQVM::CLOSURE_OP()...

    if((nouters = func->_noutervalues)) {
        for(SQInteger i = 0; i<nouters; i++) {
            SQOuterVar &v = func->_outervalues[i];
            switch(v._type){
            case otLOCAL: // outer local stack target, might be possible to use for general references
                FindOuter(closure->_outervalues[i], &STK(_integer(v._src)));
                break;
            case otOUTER:
                closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];
                break;
            }
        }
    }

And setup "references" in _OP_PREPCALL so the reference stack is setup before the function gets called,

Any idea for how to extend the outer system and implement references? It would be really cool for Squirrel.

RizzoRat commented 5 days ago

No need to, see WEAKREF. Also Squirrel always works with references by default for arrays, tables, class instances and classes. Hence. put your variable in a table, pass the table and you have your reference including all variables and objects in that table. If you want to protect other objects, uses classes instead of tables. If you don't want to reference, use CLONE (which can get costly BTW) Note that basically even the code always is in a table, including its variables (see for example THIS and BIND) unless they're declared LOCAL (which are on the stack, that's why there's outers)

Peach1 commented 4 days ago

No need to, see WEAKREF.

Weakref cannot work because obj_delegate_weakref simply copies integers. SQOBJECT_REF_COUNTED is false for integer and float types, meaning integer references aren't possible in default Squirrel.


We will modify Squirrel to make the VM instructions support arbitrary references.

function mod(&x) { x = 5; }  local x = 0; mod(x); print(x);

will output:

5

We know existing-Squirrel cannot do this, but Squirrel is open source so we're looking for comments on how to implement integer references natively in Squirrel's C++ code.

Our users want to directly modify integers by reference, without using a wrapper.

Again, the closest thing is _OP_SETOUTER _OP_GETOUTER.

Using Squirrel's Outer system, we can extend Squirrel to support general references. It requires editing sqvm.cpp and sqcompiler.cpp

Take Squirrel's Outer and extend it to full references on integers and any script local.

local x = 0; function mod() { x = 5; } mod(); print(x) // x is now 5

With some modification true references can be added on top of Squirrel's Outer system:

function mod(&x) { x = 5; }  local x = 0; mod(x); print(x);

We will redesign Squirrel's C++ code to accommodate this feature.

function mod
-----OUTERS
0 x
-----Instructions
    [000]         _OP_LOADINT 5
    [001]        _OP_SETOUTER 255 0[x]  // could be extended to support true references
    [002]       _OP_LOADNULLS 1 1
    [003]          _OP_RETURN 255 0
local x = 0; function mod() { x = 5; } mod(); print(x) // x is now 5