Search code examples
javaloopsrecursionscriptengine

Defining variable with ScriptEngineManager in java


I have the following class

class ListNode
{
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

Hopefully, it's self-explanatory, val is an integer (value of the node), and next refers to the next node.

I've also got the following method which is supposed to take char[] as an argument, reverse it and return ListNode.

To illustrate the behaviour with an example - here's one.

Let's say the method takes new char[]{'0', '8', '7'}, so it should return ListNode with the first node that has the value of 7 (as int), .next property of the node should be new node with .val of 8, and .next.next has to be a node in which val is 0.

To accomplish that I wrote the following method:

public static ListNode addTwoNumbersTo(char[] finalDigitsToReverse)
{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("js");

    int finalDigitsArrayLength = finalDigitsToReverse.length;

    ListNode finalNode = new ListNode();

    if (finalDigitsArrayLength > 0)
    {
        finalNode.val = Integer.parseInt(String.valueOf(finalDigitsToReverse[finalDigitsArrayLength - 1]));

        int j = 1;
        for (int i = finalDigitsArrayLength - 2; i >= 0; i--)
        {
            try
            {
                // Here I'm desperately trying to set .next property and calculate how many .nexts I need
                engine.eval(returnNumberOfNexts(j));
            }
            catch (ScriptException e)
            {
                System.out.println(e);
            }

            j++;
        }
    }

    return finalNode;
}

And also a method to count how many .nexts I need

public static String returnNumberOfNexts(int nextCounter)
{
    String finalDotNextString = "finalNode";

    if (nextCounter > 0)
    {
        for (int i = 0; i < nextCounter; i++)
        {
            finalDotNextString += ".next";
        }
    }

    finalDotNextString += " = new ListNode(Integer.parseInt(String.valueOf(finalDigitsToReverse[i])));";

    return finalDotNextString;
}

But it gives me the following error:

javax.script.ScriptException: ReferenceError: "finalNode" is not defined in <eval> at line number 1

So, it's all about fixing the defining variables. But the question is how to do the defining.

I apologise for this terrible code but that's the best I could come up with. Using temp variables and updating them in a loop is the worst thing in programming. It's just over my head, I have no idea how it works, it's not human-readable all in all. So I want to use just one variable and make my own solution work. Spent 3 good days on it and I don't want to give up.

BTW, it's part of a problem on leetcode Add Two Numbers


Solution

  • Hmmm, so you know this is about the missing variable? I will repeat myself, especially since this question carries the much better analyzed question in the title.

    Your scriptengine fails when it tries to resolve the 'finalNode' variable. The reason is that finalNode is known in Java but not in the Javascript engine. So you need to tell the scriptengine how to resolve the variable. I did not test the code but it might look somewhat like this:

    ListNode finalNode = new ListNode();
    ScriptEngine engine = manager.getEngineByName("js");
    Bindings bindings = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
    if (bindings==null) {
        bindings = engine.createBindings();
        engine.setBindings(ScriptContext.GLOBAL_SCOPE);
    }
    bindings.put("finalNode", finalNode);
    engine.eval(codeToExecute);