duktape icon indicating copy to clipboard operation
duktape copied to clipboard

Is there any way to reproduce GV("abc") = 123 ?

Open voinokin opened this issue 6 years ago • 4 comments

We're currently in process of moving from MS JScript (ActiveScripting) we use in our system to your script engine. MS JScript engine somehow supports the assignment statements GV("abc") = 123, where GV is some named values container (implemented in COM with IDispatch interface). Note that ( + ) and not [ + ] are used for properties access - I believe this is MS custom extension to the language. To my understanding in normal ECMAScript GV("abc") always means a function call.

There are cases in our scripts when the result of GV("abc") is operated like reference so that post- and pre-increment/decrements are possible (eg. GV("abc")++). But such cases are much less important due to their rarity and possibility to be converted to normal GV("abc") = GV("abc") + 1 manually).

Due to amount of scripts already created for JScript engine, I wonder whether there is any way with duktape engine to define GV as function (or somehow else) that would return something (reference?) on top of values stack making further assignment to it work the way it works in JScript. Please disregard any COM and IDispatch bindings I mentioned above - something that would just set property on target script object will do.

At the moment duktape source code tells me to consider inserting some custom modification to 3 places within duk_js_compiler file where it currently emits op-code DUK_OP_INVLHS - namely close to 'postincdec', 'preincdec', and 'assign' labels. Is there any better way to do this without modifying duktape source code?

Thank you.

voinokin avatar Oct 08 '19 16:10 voinokin

The specification allows custom LHS expressions where e.g. a function returns an LHS compatible value. There are no such standard values and Duktape doesn't unfortunately currently support such LHS values.

If something like that was added it would ideally be something that was relatively generic.

Thinking out loud as an example: maybe the assignment operator could allow an object LHS value if the object contained some magic Symbol value handling assignment, e.g.:

var assignmentHandler = Symbol.for('lhsAssign');

function myLhs() {
    return { [assignmentHandler] = function (v) { print('assigned:', v); } }
}

This could be made to have relatively little cost because the extra Symbol check would only come into play in the code paths where Duktape currently executes INVLHS anyway.

svaarala avatar Oct 09 '19 00:10 svaarala

Regarding the 'special type' of value being operated - the only thing I can think of now is heapptr. I.e. for my case GV may be implemented as a function that returns heapptr to its argument value (the name of the contained item). Then, duktape may support more granular INVLHS behavior for (at least) 'postincdec', 'preincdec' and 'assign' branches checking that LHS is heapptr and invoking new external callback if it is installed instead of just throwing exception. The callback may be something like duk_ret_t (duk_nonstd_op*)(uint opCode), and opCode may be defined as an enumeration including DUK_NONSTD_OP_INVLHS_INC, DUK_NONSTD_OP_INVLHS_DEC, DUK_NONSTD_OP_INVLHS_ASSIGN and DUK_NONSTD_OP_GETVALUE for now. The DUK_NONSTD_OP_GETVALUE is required for cases when any value processing operation meets heapptr for any of its arguments - it would just resolve such argument thru callback to the actual value on stack. Such installed callback then operates obviously for my case - it would ++, --, assign RHS to LHS (implies 2 items on stack), or return contained value.

A bit hackish, but anyway - what do you think? Perhaps there will be other cases in the future when non-standard behavior would be required.

voinokin avatar Oct 10 '19 09:10 voinokin

The specification allows custom LHS expressions where e.g. a function returns an LHS compatible value.

FWIW, I think this was explicitly disallowed in ES6.

fatcerberus avatar Oct 30 '19 18:10 fatcerberus

@fatcerberus You're correct, ES2015 includes this change:

6.2.3: In ECMAScript 2015, Function calls are not allowed to return a Reference value.

I wouldn't mind supporting it though, but it would need to be clean and generalized.

svaarala avatar Nov 04 '19 09:11 svaarala