Get last evaluated expression inside function - java

This is related to this other question:
Last evaluated expression in Javascript
But I wanted to provide more details about what I wanted to do and show how I finally solved the problem as some users requested in the comments.
I have snippets of Javascript that are written by users of my app. This snippets need to go to a kind of template like this:
var foo1 = function(data, options) {
<snippet of code written by user>
}
var foo2 = function(data, options) {
<snippet of code written by user>
}
...
Expressions can be very different, from simple things like this:
data.price * data.qty
To more complex tings like this:
if (data.isExternal) {
data.email;
} else {
data.userId;
}
The value returned by the function should be always the last evaluated expression.
Before we had something like this:
var foo1 = function(data, options) {
return eval(<snippet of code written by user>);
}
But due to optimizations and changes we are making, we cannot keep using eval, but we need to return the last evaluated expression.
Just adding a 'return' keyword won't work because expressions can have several statements. So I need to make those functions return the last evaluated expressions.
Restrictions and clarification:
I cannot force users to add the 'return' keyword to all the scripts they have because there are many scripts written already and it is not very intuitive for simple expressions like 'a * b'.
I'm using Java and Rhino to run Javascripts on server side.

As people pointed out in Last evaluated expression in Javascript, getting the last evaluated expression is not possible in standard Javascript.
What I finally ended up doing, as suggested by FelixKling, was to manipulate the AST of the script written by the user. This way I store the user written script and the modified version, which is the one I finally run.
For manipulating the AST I used Rhino and basically modify all EXPR_RESULT nodes to store the result in a variable that I finally return at the end of the script. Here is the code to do that:
public class ScriptsManipulationService {
private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);
public String returnLastExpressionEvaluated(String script) {
Parser jsParser = new Parser();
try {
AstRoot ast = jsParser.parse(script, "script", 1);
ast.getType();
ast.visitAll(new NodeVisitor() {
#Override
public boolean visit(AstNode node) {
if (node.getType() == Token.EXPR_RESULT) {
ExpressionStatement exprNode = (ExpressionStatement) node;
Assignment assignmentNode = createAssignmentNode("_returnValue", exprNode.getExpression());
assignmentNode.setParent(exprNode);
exprNode.setExpression(assignmentNode);
}
return true;
}
});
StringBuilder result = new StringBuilder();
result.append("var _returnValue;\n");
result.append(ast.toSource());
result.append("return _returnValue;\n");
return result.toString();
} catch (Exception e) {
logger.debug(LogUtils.format("Error parsing script"), e);
return script;
}
}
private Assignment createAssignmentNode(String varName, AstNode rightNode) {
Assignment assignmentNode = new Assignment();
assignmentNode.setType(Token.ASSIGN);
Name leftNode = new Name();
leftNode.setType(Token.NAME);
leftNode.setIdentifier(varName);
leftNode.setParent(assignmentNode);
assignmentNode.setLeft(leftNode);
rightNode.setParent(assignmentNode);
assignmentNode.setRight(rightNode);
return assignmentNode;
}
}
This way, if you pass the following script:
data.price * data.qty;
You will get back:
var _returnValue;
_returnValue = data.price * data.qty;
return _returnValue;
Or if you pass:
var _returnValue;
if (data.isExternal) {
_returnValue = data.email;
} else {
_returnValue = data.userId;
}
return _returnValue;
Please keep in mind that I haven't done an exhaustive testing and will be polishing it over time, but this should show the general idea.

Related

How to store function handles from ScriptManager for later usage?

tl;dr:
How do/can I store the function-handles of multiple js-functions in java for using them later? Currently I have two ideas:
Create multipe ScriptEngine instances, each containing one loaded function. Store them in a map by column, multiple entries per column in a list. Looks like a big overhead depending on how 'heavy' a ScriptEngine instance is...
Some Javascript solution to append methods of the same target field to an array. Dont know yet how to access that from the java-side, but also dont like it. Would like to keep the script files as stupid as possible.
var test1 = test1 || [];
test1.push(function(input) { return ""; });
???
Ideas or suggestions?
Tell me more:
I have a project where I have a directory containing script files (javascript, expecting more than hundred files, will grow in future). Those script files are named like: test1;toupper.js, test1;trim.js and test2;capitalize.js. The name before the semicolon is the column/field that the script will be process and the part after the semicolon is a human readable description what the file does (simplified example). So in this example there are two scripts that will be assigned to the "test1" column and one script to the "test2" column. The js-function template basically looks like:
function process(input) { return ""; };
My idea is, to load (and evaluate/compile) all script files at server-startup and then use the loaded functions by column when they are needed. So far, so good.
I can load/evaluate a single function with the following code. Example uses GraalVM, but should be reproducable with other languages too.
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
final Invocable invocable = (Invocable) engine;
engine.eval("function process(arg) { return arg.toUpperCase(); };");
var rr0 = invocable.invokeFunction("process", "abc123xyz"); // rr0 = ABC123XYZ
But when I load/evaluate the next function with the same name, the previous one will be overwritten - logically, since its the same function name.
engine.eval("function process(arg) { return arg + 'test'; };");
var rr1 = invocable.invokeFunction("process", "abc123xyz"); // rr1 = abc123xyztest
This is how I would do it.
The recommended way to use Graal.js is via the polyglot API: https://www.graalvm.org/reference-manual/embed-languages/
Not the same probably would work with the ScriptEngine API, but here's the example using the polyglot API.
Wrap the function definition in ()
return the functions to Java
Not pictured, but you probably build a map from the column name to a list of functions to invoke on it.
Call the functions on the data.
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value toUpperCase = context.eval("js", "(function process(arg) { return arg.toUpperCase(); })");
Value concatTest = context.eval("js", "(function process(arg) { return arg + 'test'; })");
String text = "HelloWorld";
text = toUpperCase.execute(text).asString();
text = concatTest.execute(text).asString();
System.out.println(text);
}
}
}
Now, Value.execute() returns a Value, which I for simplicity coerce to a Java String with asString(), but you don't have to do that and you can operate on Value (here's the API for Value: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html).

rxjava2 - if else on Maybe

I am looking for what is the recommended practice in rxjava2 to handle a case where one flowable leads to conditional behaviors.
More concretely, I have a Maybe<String> for which I want to Update the String on the database if the String exists or, if it doesn't exists I want to create a new String and save it on the database.
I thought of the below but obviously it is not what I am looking for:
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar"))).subscribe(result ->
System.out.println("save to database "+result));
source.subscribe(result -> System.out.println("update result "+result));
The above obviously produces
save to database foo
update result foo
I tried also the below which gives the expected result but still feel it's... weird.
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar")).doOnSuccess(result ->
System.out.println("save to database "+result))).subscribe();
source.doOnSuccess(result -> System.out.println("update result "+result)).subscribe();
How can I have an action for when the result exists and when it doesn't exists? How is that use case supposed to be handled in rxjava2?
Update 01
I tried the below and it looks cleaner than what I came up with above. Note sure it is recommended rxjava2 practice however...
Maybe.just(new String("foo"))
.map(value -> Optional.of(value))
.defaultIfEmpty(Optional.empty())
.subscribe(result -> {
if(result.isPresent()) {
System.out.println("update result "+result);
}
else {
System.out.println("save to database "+"bar");
}
});
You have the isEmpty() operator that will return you Boolean if the Maybe source is empty or not, and then you can flatMap it and write a if else statement depending on that Boolean
This is a common pattern in our code as well, though in our case the choices are themselves async. You can't get quite the right semantic by simply composing flatMapX and switchIfEmpty (in either order), so I am curious why this isn't part of the API.
Here's what we're doing for now (this example for when the 2 options are both Completables, we have similar things for the other types as well):
public static <T> Completable flatMapCompletable(Maybe<T> target,
#ClosureParams(FirstParam.FirstGenericType.class)
Closure<? extends CompletableSource> completableSupplier,
Supplier<CompletableSource> emptySupplier) {
Maybe<T> result = target.cache();
return result.isEmpty().flatMapCompletable(empty -> {
if (empty) {
return emptySupplier.get();
} else {
return result.flatMapCompletable(completableSupplier::call);
}
});
}
We're using Groovy, so we package these up as extension methods. I'm not thrilled with the need to use cache() so I'm wondering if there is a better alternative. From looking at the code, an operator which basically combines flatMapX and switch looks like it wouldn't be too hard (but I feel like I'm missing something).
Try something like this. checkDB can return a Maybe or Single or whatever which emits either an optional or a wrapper Object.
checkDB(String)
.flatMap(s -> {
if (s.isPresent()) {
return updateDB(s.get());
} else {
return insertDB("new String");
}
})
There is an solution using the flatMap call with 3 params
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
Function {
update(message) // onSuccess update call returns Single
},
Function {
Single.error(it) // onError
},
Callable {
add(message) // onComplete add call returns Single
}
)
}
}
Or shorter version
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
{
update(message) // onSuccess update call returns Single
},
{
Single.error(it) // onError
},
{
add(message) // onComplete add call returns Single
}
)
}
}

Parse if else statement using Compiler Tree API

I am trying to find a way to parse java code source in netbeans using the Tree API, I learned through this guide how I can access high level language elements (classes,methods,fields ..).
what I'm looking for is a way to parse if else statements (for a start) since I'm trying to apply replace type code with state strategy refactoring afterwards. it is very important for me to get the if condition. Any help would be deeply appreciated.
After diving into the Compiler Tree API doc I found how to access low level code the condition of a selected if statement in my case, here is a code snippet
#Override
public Void visitIf(IfTree node, Void p) {
try {
JTextComponent editor = EditorRegistry.lastFocusedComponent();
if (editor.getDocument() == info.getDocument()) {
InputOutput io = IOProvider.getDefault().getIO("Analysis of " + info.getFileObject().getName(),
true);
ExpressionTree exTree = node.getCondition();
if (exTree.getKind() == Tree.Kind.PARENTHESIZED) {
ParenthesizedTree parTree = (ParenthesizedTree) exTree;
BinaryTree conditionTree = (BinaryTree) parTree.getExpression();
ExpressionTree identTree = conditionTree.getLeftOperand();
if (identTree.getKind() == Tree.Kind.IDENTIFIER) {
Name name = ((IdentifierTree) identTree).getName();
io.getOut().println("Hurray, this is the name of the identifier in the left operand: " + name.toString());
}
io.getOut().close();
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
return null;
}
Thankfully the code naming is intuitive otherwise the documentation doesn't help much. debugging using println is very useful to know what kind of tree to deal with next.

Assigning variable to java list in play framework 2.0

I need to access a Java list from html code in play.
My list is returned by a public static method:
ComboboxOpts.getListOfValues()
I am using this method several times in my scala code want to assign it to some variable. Maybe something similar to this
#mylist = ComboboxOpts.getListOfValues()
So that I can use it like this
#for(i <- 0 to mylist.size -1){
//Do stuff
}
rather than this
#for(i <- 0 to ComboboxOpts.getListOfValues.size -1){
//Do stuff
}
You can use defining() to set new variables, such as:
#defining(getName() + " " + getType()) { text =>
Hello #text!
}
However, for your case, you can just iterate over a list as follows:
#for(value <- ComboboxOpts.getListOfValues()) {
<li>#value</li>
}
This will not call your function repeatedly, and is much more expressive. The Play documentation has several related examples: http://www.playframework.org/documentation/2.0/JavaTemplates
If you absolutely need the index as well, try using Scala's zipWithIndex().
Application.java file
public class Application extends Controller {
public static Result index() {
List myList = new ArrayList();
myList.add("one");
myList.add("two");
return ok(index.render(myList));
}
}
index.scala.html file
#(myList: List[String])
#main("Welcome to Play 2.0") {
#for(item
#item
}
}

Reformatting code with Regular Expressions

We have an ArrayList of items in several classes which are giving me trouble every time I'd like to insert a new item into the list. It was a mistake on my part to have designed the classes in the way I did but changing the design now would be more headache than it's worth (bureaucratic waterfall model.) I should have anticipated format changes to the documents the customer was supplying us waterfall be damned.
I'd like to write a simple script in python which goes into a class, adds the item to the list, and then increments all retrievals for the following items. That doesn't sound very explanatory:
Foo extends Bar{
public Foo(){
m_Tags.add("Jane");
m_Tags.add("Bob");
m_Tags.add("Jim");
}
public String GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
public String GetBob() { return m_ParsedValue.get( m_Tags.get(2) ); }
public String GetJim() { return m_ParsedValue.get( m_Tags.get(3) ); }
}
You see if I want to add a value between "Jane" and "Bob" I then have to increment the integers in the Get* functions. I just want to write a simple script in Python that does the work for me. Someone I very much respect suggested regex.
Edit:
Yes, LinkedHashMap. So simple, so easy and so not in the design specs now. I hate waterfall. Hate it with a passion. This whole bit was a "small" and "easy" part that "shouldn't take much time to design." I made mistakes. It's stuck in stone now.
You want your regular expression to be as flexible as the compiler will be with respect to whitespace between tokens. Doing so and mimicking whitespace usage makes the pattern pretty messy. The code below (sorry: Perl, not Python) edits your source files in-place.
#! /usr/bin/perl -i.bak
use warnings;
use strict;
my $template =
'^( public
String
Get)(\w+)( \( \) { return
m_ParsedValue . get \( m_Tags . get \( )(\d+)( \) \) ; } )$';
$template =~ s/ +/\\s*/g;
$template =~ s/(\r?\n)+/\\s+/g;
my $getter = qr/$template/x;
die "Usage: $0 after new-name source ..\n" unless #ARGV >= 3;
my $after = shift;
my $add = shift;
my $index;
while (<>) {
unless (/$getter/) {
print;
next;
}
my($abc,$name,$lmno,$i,$xyz) = ($1,$2,$3,$4,$5);
if (defined $index) {
print join "" => $abc, $name, $lmno, ++$index, $xyz;
}
else {
if ($name eq $after) {
$index = $i;
print; print join "" => $abc, $add, $lmno, ++$index, $xyz;
}
else { print; }
}
}
For example,
$ ./add-after Jane Foo code.java
$ cat code.java
Foo extends Bar{
public Foo(){
m_Tags.add("Jane");
m_Tags.add("Bob");
m_Tags.add("Jim");
}
public String GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
public String GetFoo() { return m_ParsedValue.get( m_Tags.get(2) ); }
public String GetBob() { return m_ParsedValue.get( m_Tags.get(3) ); }
public String GetJim() { return m_ParsedValue.get( m_Tags.get(4) ); }
}
Don't do this with regexp. Create symbolic constants (using for example an enum) that map the names to numbers.
Comments about bad-practices apart - here is the code you asked in the language you asked for.
The best thing if you are keeping the system this way, probably would be to make these java files be automatically generated in the build process itself -- you 'd just keep a names list in a .txt file in the directory. This script is suitable to do that.
(It won't modify your files, it genrate new ones based on the template you posted here)
import re, sys
template = """Foo extends Bar{
public Foo(){
%s
}
%s
}
"""
tag_templ = """ m_Tags.add("%s");"""
getter_templ = """ public String GetJane() { return m_ParsedValue.get( m_Tags.get(%d) ); }"""
def parse_names(filename):
data = open(filename).read()
names = re.findall(r'm_Tags\.add\("(.*?)"', data)
return names
def create_file(filename, names):
tag_lines = [tag_templ % name for name in names]
getter_lines = [getter_templ % (i + 1) for i in range(len(names))]
code = template % ("\n".join(tag_lines), "\n".join(getter_lines))
file = open(filename,"wt")
file.write(code)
file.close()
def insert_name(after, new_name, names):
names.insert(names.index(after) + 1, new_name)
if __name__ == "__main__":
if len(sys.argv ) < 4:
sys.stderr.write("Usage: changer.py <filename> <name-before-insertion> <new-name>")
sys.exit(1)
filename, name_before, new_name = sys.argv[1:]
names = parse_names(filename)
insert_name(name_before, new_name, names)
create_file(filename, names)
I'm doing this (well, something very similar) right now, but using Excel and VBA macros. All of the Business Values are organized and ordered in a spreadsheet. I just have to click a button to generate the appropriate code for the selected cells, then copy-paste to the IDE. Better yet, I have several "code columns" for each row. Some of them generate queries, some XSL transformations, and some procedures. For one row of business data, I can get all three types of generated code very easily.
I found this (re-generate) to be MUCH easier than re-formatting the existing code I had.

Categories

Resources