How to invoke script function with parameters?

Jan 12, 2010 at 12:16 PM

I'd like to do something similar to an event, like onClick on a web page. I stumbled when I try to invoke a script function. It seems there's no method on JintEngine to invoke a funtion besides Run(). But Run() cannot take parameters.

For simple numbers, I can generate a string of the script function call. But .NET objects cannot be passed by string to the script. So, my question is how to do that? Or it will be supported in the next release? ;-)

Coordinator
Jan 12, 2010 at 12:19 PM

Hi qrli,

You can do so since the very first version of Jint using the function SetParameter.

Jan 12, 2010 at 1:39 PM

Hmm... You mean use SetParameter() to set variables and then Run() a function call with those variables as parameters?

Sounds OK, but what if the parameter names clash with global variables in the script?

In my case, I load a javascript file with several functions and of course global variables to store some states. Then on some event, I call into the script function.

Coordinator
Jan 12, 2010 at 2:00 PM

I'm not sure of what you really want to do, but can't simply rename them (either the global variables or the parameters you give to the JintEngine) ?

Otherwise, you should provide some sample in order to make us understand better your issue.

Jan 13, 2010 at 3:49 AM

Yes, renaming the parameters is a reasonable workaround.

To invoke a script function "someEventHandler", I can

SetParameter("__arg1", eventArg1);
SetParameter("__arg2", eventArg2);
...
Run(funcName + "(__arg1, __arg2, ...)");

What I'm trying to do is to encapsulate those into a general

object Invoke(string funcName, params object[] args)

So that I can call Invoke("someEventHandler", eventArg1, eventArg2, ...) with any script function. I just feel it is a bit of overkill to involve global variables and re-parse the call string for every call. Did I make myself clear now?

PS: Actually I'm trying to migrate from LuaInterface to Jint.

Coordinator
Jan 13, 2010 at 7:36 AM

Hi,

I now understand what you want to do. We have some internal mechanism. I am currently trying to expose it. It will be on the source repository by this Week-end I think.

Jan 13, 2010 at 7:38 AM

Hi grli,

I have some experimental code that does what you're trying to do.  Basically, I need to create my own ExecutionVisitor.  I learned to do this by inspecting the source code for Run():

In this source code file (http://bitbucket.org/gwbasic/objectcloud/src/tip/Server/ObjectCloud.Javascript.Jint/ScopeWrapper.cs), I inspect the scope to find flagged functions.  You could probably adapt this to find them by name:

        /// <summary>
        /// The execution visitor
        /// </summary>
        public ExecutionVisitor ExecutionVisitor
        {
            get { return _ExecutionVisitor; }
        }
        private readonly ExecutionVisitor _ExecutionVisitor = new ExecutionVisitor();

        /// <summary>
        /// The global scope
        /// </summary>
        public JsDictionaryObject GlobalScope
        {
            get { return _ExecutionVisitor.GlobalScope; }
        }
This loads the script into a scope:
            Program program = JintEngine.Compile(script, false);

            if (program == null)
                throw new
                    ArgumentException("Script can't be null", "script");

            ExecutionVisitor.DebugMode = false;
            ExecutionVisitor.PermissionSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);

            try
            {
                ExecutionVisitor.Visit(program);

Here I'm creating a FunctionCaller object, which is a class that I use to call Javascript functions.

           foreach (string globalKey in GlobalScope.GetKeys())
            {
                JsInstance globalValue = GlobalScope[globalKey];

                // If the value is a Javascript function...
                if (globalValue is JsFunction)
                {
                    string method = globalKey.ToString();
                    JsFunction javascriptMethod = (JsFunction)globalValue;
                        FunctionCaller functionCaller = new FunctionCaller(this, TheObject, method, javascriptMethod);

FunctionCaller's source code is here:  http://bitbucket.org/gwbasic/objectcloud/src/tip/Server/ObjectCloud.Javascript.Jint/FunctionCaller.cs

A FunctionCaller (in my program) essentially encapsulates a JsFunction object from Jint.

                      
                       JsInstance[] parsedArguments = new JsInstance[ArgnameToIndex.Count];
(You will need to convert your arguments to Js... types)
                        JavascriptMethod.Execute(ScopeWrapper.ExecutionVisitor, ScopeWrapper.GlobalScope, parsedArguments);
                        JsInstance callResults = ScopeWrapper.ExecutionVisitor.Result;

Coordinator
Jan 13, 2010 at 8:21 AM

Hi,

I have just implemented it and commited it on the svn repository.

@gwbasic, I did not need to change any line in the ExecutionVisitor. I would say your approach might not be straight forward enough ;)

Jan 13, 2010 at 11:37 AM

wow cool.

I tried to checkout the latest repository from svn, but I got a empty folder. I'm wondering if I've done some mistake...

 

Coordinator
Jan 13, 2010 at 12:21 PM

Hi qrli,

This must be because you tried the svn repository of codeplex. We are using our own svn repository.

Here are the information to connect to it :

https://svn.evaluant.com:8443/svn/jint

l/p: svnuser/svnuser

Jan 13, 2010 at 12:52 PM

It is awesome! Thanks very much.