paulbartrum / jurassic

A .NET library to parse and execute JavaScript code.
MIT License
868 stars 121 forks source link

Inspect variables bound in closure #197

Open lsim opened 3 years ago

lsim commented 3 years ago

Is there any way to list or otherwise access variables bound in the current functional scope when javascript calls back to C#?

This would be beneficial for people wanting to build an interactive debugger for js running on jurassic. At present we are limited to showing global variables. It would be nice if there was some way to accomplish this for scoped variables as well.

paulbartrum commented 3 years ago

I recently rewrote how scoped variables work. If you have a reference to the current RuntimeScope you can just call runtimeScope.GetValue(variableName). Unfortunately there can be many scope instances in a single method and there's no way to know which scope is the correct one at runtime (the compiler keeps track of this during compilation).

lsim commented 2 years ago

Sounds promising - iterating through a number of scopes might work fine, if it's possible to get a list of them.

Last we checked, we were unfortunately unable to upgrade our Jurassic 2.2.2 since we evaluate lodash.js into the js-environment, and a regression a while back made that fail. That issue is still open, so we're probably still stuck.

paulbartrum commented 2 years ago

@lsim I did a fix for the lodash symbol issue, it's in version 3.2.4.

lsim commented 2 years ago

Great! We'll have another go then. Closure variable access will make a nice improvement to our debugger.

lsim commented 2 years ago

I recently rewrote how scoped variables work. If you have a reference to the current RuntimeScope you can just call runtimeScope.GetValue(variableName). Unfortunately there can be many scope instances in a single method and there's no way to know which scope is the correct one at runtime (the compiler keeps track of this during compilation).

I seem to have successfully upgraded to 2.3.6. 🎉

I'm now trying to figure out how to get a reference to the current RuntimeScope in a [JsFunction]-annotated C# method invoked from js-country. I had a look at references to RuntimeScope in the jurassic sources but I didn't spot any actionable clues.

Is there an example somewhere I could look at?

paulbartrum commented 2 years ago

I seem to have successfully upgraded to 2.3.6. 🎉

You mean 3.2.6? Great 👍

I'm now trying to figure out how to get a reference to the current RuntimeScope in a [JsFunction]-annotated C# method invoked from js-country.

The short answer: you can't. What do you need this for, exactly? The RuntimeScope class is used to implement variable scopes in nested functions and with statements; it should not be relevant inside your C# method...?

lsim commented 2 years ago

Oops - yes: 3.2.6

We have in our platform various features aimed at making debugging user scripts easier. It currently allows inspecting root scope variables only. With access to the current RuntimeScope, we might be able to allow interaction with variables in other scopes also.

paulbartrum commented 2 years ago

That makes sense. Unfortunately I haven't made this easy. There's a few options but none of them are particularly nice: 1) Build your own private copy of Jurassic. Then you can change it how you like (at the expense of making upgrading harder). 2) UserDefinedFunction has an internal RuntimeScope ParentScope property, which you could access via reflection. A UserDefinedFunction instance is created whenever you define a function in JS -- so you could define it in the global scope using Execute() and then get a reference to it using GetGlobalVariable(). 3) ArgumentsInstance has a private RuntimeScope bindings which is also accessible via reflection. You can get a ArgumentsInstance instance by passing in "arguments" to your function.

Yeah, not great, sorry :-/