How to get variable values define inside a function using Rhino? - rhino

When I run this java code, i am able to get the values of variables define outside the function, but i am unable to get the values of variable define inside the function. how to access these variable values?
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
public class JSFunctionTest {
public static void main(String args[]) {
String code = "var name='nc',global_a = 'jill'; " + "\n"+
"function myfunc(b) { " + "\n"+
"var local_a = 1;" + "\n"+
"global_a = 'jack';" + "\n"+
" return b;" + "\n"+
"}";
Context context = Context.enter();
context.setGeneratingDebug(true);
context.setOptimizationLevel(-1);
Scriptable scope = context.initStandardObjects();
context.evaluateString(scope, code, "code", 1, null);
//getting values of varables
System.out.println("var name:"+scope.get("name", scope));
System.out.println("var global_a:"+scope.get("global_a", scope));
System.out.println("var local_a:"+scope.get("local_a", scope));//not found becase function wasnt run
//calling the function.
Object fObj = scope.get("myfunc", scope);
if (!(fObj instanceof Function)) {
System.out.println("myfunc is undefined or not a function.");
} else {
Object functionArgs[] = { "nc" };
Function f = (Function)fObj;
Object r = f.call(context, scope, scope, functionArgs);
String report = "myfunc('nc') = " + Context.toString(r);
//trying to access global and local a after calling function
System.out.println("var global_a:"+scope.get("global_a", scope));//values is changed, because this is defined out side the function.
System.out.println("var local_a:"+scope.get("local_a", scope));// still not found,after running the function.
System.out.println(report);
}
}
}

I was able to resolve this, by implementing a debugger using the debug API in Rhino.
Implement your own debugger and debugframe classes.
Hook them to your context using setDebugger() method
in the DebugFrame class, I have implemented. cache the scope object in the onEnter method.
in the onLineChange method, you can get the local variables using ScriptableObject.getProperty() passing the cache scope object and giving the names

In ECMAScript, functions create their own scope. Outside the global scope, it's the only way to create new ones. See Rhino Scopes and Contexts for an example similar to yours.
The thing is that ECMAScript is a dynamic language (especially when optimization level is set to interpreted mode). This means the interpreter does not know in advance what it will encounter. The function's scope is only created/evaluated when the code is actually executed. So you can't evaluate a piece of code and query for variables inside a scope that isn't executed.
The question is why would you want to do that in practice? For debugging, you can step into the code and inspect the scopes, you should be able to see it.

Related

access arguments similar to this.variable

void main() {
doStuff("foo");
}
void doStuff(String myString) {
String myString = "bar";
print(myString); //prints "bar"
}
The above executed in the dartpad yields "bar", the local variable is used instead of the parameter in the last line. If instead of an argument myString were an instance variable of a class, we could access the original myString with this.myString to print "foo". Is there an analogous way to access an argument to a function after a homonymous local variable has been declared?
No.
For local variables, you are expected to be able to rename any local variable which shadows the variable you want to access, so there is no scope override.
For instance variables, you can use this.x, for static variables you can use ClassName.x, for an imported top-level name, you can import the library with a fresh prefix name and access it as prefix.x, and for public top-level variable of the current library, you can, if all else fails, import that library with a prefix too and use:
// library foo.dart
import "foo.dart" as toplevel; // <- this library!
// ...
int foo = 42;
// ...
int method(int foo) {
return toplevel.foo + foo; // Wohoo
For local variables, you just have to rename the one that's shadowing the variable you want. Since nobody can see local variables from outside the method, no-one will ever know.

Jenkins file, check if Globals variable exists

I have jenkinsfile with defined Globals varible for timeout
class Globals {
static String TEST_TIMEOUT = ""
}
I am using functions from shared library
I am using the global variable to set a timeout for function. Since the shared library used by other projects that doesn't define the Globals variable I defined environment variable in the function file to be used as default value for time out.
env.TESTS_TIME_OUT="10080"
Then in function I want to check if Globals variable exists, I want to use the value as time out, if not the to use the default value.
if(Globals.TEST_TIMEOUT){
env.TESTS_TIME_OUT= "${Globals.TEST_TIMEOUT}"
}
timeout(time: "${env.TESTS_TIME_OUT}", unit: 'MINUTES') {
.
.
.
}
I`ve done it before with success on env parameters, but this time I am getting an error
No such field found: field java.lang.Class TEST_TIMEOUT
Any ideas how to solve this ? Or Any other way to check if Globals variable exists ?
Thank you
You can catch groovy.lang.MissingPropertyException which will be thrown if either Globals or Globals.TEST_TIMEOUT does not exist:
try {
env.TESTS_TIME_OUT = Globals.TEST_TIMEOUT
}
catch( groovy.lang.MissingPropertyException e ) {
env.TESTS_TIME_OUT = "10080"
}
You could even move this pattern into a generic function...
def getPropOrDefault( Closure c, def defaultVal ) {
try {
return c()
}
catch( groovy.lang.MissingPropertyException e ) {
return defaultVal
}
}
... which could be called like this:
env.TESTS_TIME_OUT = getPropOrDefault({ Globals.TEST_TIMEOUT }, '10080')
This could be useful if there are many different globals that you want to treat similar. Safes you from writing many try/catch blocks.
The closure is required to make sure that the expression Globals.TEST_TIMEOUT will be evaluated inside of the try/catch block of getPropOrDefault instead of before the function call.

Analyzer package - How to recursively search in the results of parseDartFile()

Currently trying to understand 'analyzer' package, because I need to analyze and edit .dart file from another file (maybe it's a terrible idea).
I think I understand how to go deep into the childEntities tree.
But can't understand how to search in it.
I mean, theoretically I can write a recursive search that will find me a class named "FindABetterSolution". But is there a built in method for that?
What I'm trying to do:
var file = parseDartFile("test.dart");
file.childEntities.forEach((SyntacticEntity entity) {
if(entity is AstNode) {
//then it has its own child nodes which can be AstNode-s or Tokens.
} else if(entity is Token) {
Token token = entity;
print("${token.lexeme} ${token.type} ${token.runtimeType} ${token.keyword}");
//this will output "class KEYWORD KeywordToken CLASS" for "class" in "class MyClass {"
}
});
//I need a way to find certain functions/classes/variables/methods e.t.c.
var myClassNode = file.searchClass("MyClass", abstract: false);
var myMethod = myClassNode.searchMethod("myMethod", static: true);
var globalFunction = file.searchFunction("myFunc", returns: "bool");
UPD: Ok, I think I found a way to search and replace nodes. But how to insert new node after/before another?
You can call file.accept() or file.visitChildren() with a RecursiveAstVisitor that implements visitClassDeclaration, visitMethodDeclaration, or visitFunctionDeclaration.

Groovy getProperties() call invoking getter for non-existent attribute over 1000 times

Ran into this while doing a refactor. Calls to getProperties() were causing our CPU usage to spike. What we discovered is that if you have a getter without an associated attribute, when you make a call to getProperties() that getter is called over 1000 times. The fix/workaround is obvious and we know it has something to do with metaprogramming but why is this happening (what point in the groovy source)? See groovy script code below:
class tester {
int count = 0
public getVar() {
println count++ + " getVar() called!"
return var
}
}
def t = new tester()
t.getProperties()
println "done!"
You should see getVar() called over 1000 times. 1068 to be exact for us.
The question has probably already been answered in the comments but I dug a little deeper to also answer the "what point in the groovy source" part.
When you call getProperties() on the instance of tester Groovy will do its magic and finally call DefaultGroovyMethods#getProperties(Object) which (in Groovy 2.4.7) looks like this:
public static Map getProperties(Object self) {
List<PropertyValue> metaProps = getMetaPropertyValues(self); // 1
Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size());
for (PropertyValue mp : metaProps) {
try {
props.put(mp.getName(), mp.getValue()); // 2
} catch (Exception e) {
LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
}
}
return props;
}
First, Groovy determines the meta properties of the given object (see 1). This will return three properties:
var: getter only (getVar()), no setter, no field
class: getter only (inherited from Object), no setter, no field
count: getter, setter (both generated by Groovy) and field
You can easily verify this by calling t.getMetaPropertyValues().
Next, Groovy tries to get the current value of each property and puts it in a map (see 2). When it reaches var, it remembers that var has a getter (namely getVar()) and calls it. getVar() however, returns var again. For Groovy, this is the exact same property as determined in the first step. Once again, it calls its getter getVar() and the endless loop begins.
At some point, depending on the JVM, this results in a StackOverflowError, which is exactly what this site is all about :-D

Groovy object tracking for binding

I'm developing a Groovy library providing variable binding/syncronization with simple syntax and rich event handler.
Firstly I'm aiming to archive running the following:
def a = 1
def b = 1
def c = 1
a bind { b + c }
assert a==2 & b==1 & c==1
b = 3
assert a==4 & b==3 & c==1
c = -1
assert a==2 & b==3 & c==-1
I'd like avoid Java FX approach of providing additional classes but rather enhance objects with this functionality.
I'm stuck at finding some tracking of objects. Groovy doesn't feature overload of assignment expression.
Currently I see solution in heavy AST transformation (maybe dsld might help).
Maybe there is some object tracking, events or whatever, I've missed?
I'm presuming you are writing your code using scripts. Did what you wanted with the following ideas:
Instead of binding values to keys using the Script.binding, it is better if you create a Variable class which represents both the value and the variable name;
Every method called on the Variable object gets delegated to its value;
A Listener class which encapsulates a reference to the updating operation AND the Variable object which needs to be updated;
An updateListeners() method, to, well, update the listeners;
A bind(closure) method that just bypasses the closure to the variable object. It could pretty much be dropped and written as a { b + c };
class Listener { Closure operation; Variable variable }
class Variable implements GroovyInterceptable {
String name; def value
def invokeMethod(String method, args) {
def var = args[0]
var.class == Variable ?
value."$method"(var.value) : value."$method"(var)
}
}
Variable.metaClass.call = { Closure operation ->
binding['listeners'] <<
new Listener(operation: operation, variable: delegate)
updateListeners()
}
def bind(Closure operation) { operation }
def updateListeners() {
binding.listeners.each {
it.variable.value = it.operation()
}
}
void setProperty(String prop, value) {
if (!binding.hasVariable('listeners')) binding['listeners'] = []
binding[prop] = new Variable(name: prop, value: value)
updateListeners()
}
And your tests worked like a charm.

Resources