lunadir
lunadir

Reputation: 339

C#<-->JScript: invisible array?

I have a bit of a complex program which is giving me this apparently phantom error...
I'll start explaining with the help of this little example program I rigged that can throw my beautiful exception for anyone who runs it.

<!-- language: c# -->
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace so_redux {
    static class Program {
        [STAThread]
        static void Main(){
            CS2JS _class=new CS2JS();
        }
    }//class Program

    class CS2JS{
        public CS2JS(){
            Func<String,Object> js_eval=initJS();
            Object cs_ic=initCS();

            string xc;
            object res;

            cs_ic.GetType().GetMethod("init").Invoke(cs_ic,null);
            AppDomain.CurrentDomain.SetData("trespasser",cs_ic);

            xc=@"function edata(fieldname:String,ival:String):Object{
                    var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
                    var v1=sob.GetType().GetField(fieldname).GetValue(sob);

                    function HASH(s1:String,s2:String):Object{
                        var q1=sob.GetType().GetField(s1).GetValue(sob);
                        return q1.ITEM(s2);
                    }

                    var v2=v1.ITEM(ival);
                    return eval(v2);
                }
                edata('HT','foo');";
            res=js_eval(xc);
            // var xx;xx=new Hashtable();xx['sda']='1';eval(xx['sda']); OK            
        }

        Func<String,Object> initJS(){
            System.CodeDom.Compiler.CodeDomProvider jcc;
            System.CodeDom.Compiler.CompilerParameters jcp;
            System.CodeDom.Compiler.CompilerResults jcr;
            System.Reflection.Assembly jas;
            object jis;
            string code;
            Type t_ii;

            code=@"@set @debug(off)
                import System;
                import System.Collections;
                import System.Collections.Generic;
                package internal_namespace{class internal_class{
                    public function internal_method(_code:String):Object{
                        return eval(_code);
                    }
                }
            }";

            jcc=Microsoft.JScript.JScriptCodeProvider.CreateProvider("JScript");
            jcp=new System.CodeDom.Compiler.CompilerParameters();
            jcp.CompilerOptions="/fast-";
            jcp.GenerateExecutable=false;
            jcp.GenerateInMemory=true;
            jcp.IncludeDebugInformation=false;
            jcp.ReferencedAssemblies.Add("System.dll");
            jcp.ReferencedAssemblies.Add("System.Core.dll");
            jcp.WarningLevel=4;
            jcr=jcc.CompileAssemblyFromSource(jcp,code);
            jas=jcr.CompiledAssembly;
            jis=jas.CreateInstance("internal_namespace.internal_class");

            t_ii=jas.GetType("internal_namespace.internal_class");
            return (s1)=>t_ii.InvokeMember("internal_method",System.Reflection.BindingFlags.InvokeMethod,null,jis,new object[]{s1});
        }//initJS

        Object initCS(){
            var v1= Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp");
            System.CodeDom.Compiler.CompilerParameters v2=new System.CodeDom.Compiler.CompilerParameters();
            v2.GenerateExecutable=false;
            v2.GenerateInMemory=true;
            v2.IncludeDebugInformation=false;
            v2.WarningLevel=4;
            v2.ReferencedAssemblies.Add("System.dll");
            v2.ReferencedAssemblies.Add("System.Core.dll");

            string _code="public Hashtable2 HT;"+
                "public void init(){"+
                    "HT=new Hashtable2();"+
                    "HT[\"foo\"]=\"1\";"+
                    "HT[\"bar\"]=\"HASH('HT','foo')\";"+
                "}";

            var v3="using System;using System.Collections;using System.Collections.Generic;"+
                    "namespace internal_namespace{public class Hashtable2:Hashtable{"+
                        "public Hashtable2():base(){} public Hashtable2(int N):base(N){}"+
                        "public Object ITEM(Object K){return this[K];} }"+
                    "[Serializable]public class internal_class{"+
                        "public internal_class(){}"+
                        _code+
                        "\n}}";

            var v4=v1.CompileAssemblyFromSource(v2,v3);
            var v5=v4.CompiledAssembly;
            var v6=v5.GetType("internal_namespace.internal_class");
            var v7=v5.CreateInstance("internal_namespace.internal_class");

            return v7;
        }//initCS
    }//class CS2JS
}//namespace so_redux

The exception that is thrown is "index out of bounds", and it's thrown from JScript. The problem? It's that there is no array!

What this code is doing: first a JScript interpreter is initialized by compiling at runtime a class that "exports" an eval (one could do a dll, but in this case I didn't).
Then a C# assembly is compiled, an assembly that "exports" some user code (the variable _code in initCS is originally loaded by reading a text file).
After the initialization of the newly compiled class (the invoking of init()), I need the two assemblies (JScript and C#) to interact, so I need to pass data between them, and I thought of using AppDomain.
Note: in the C# assembly an Hashtable2 is defined because I put in there an ITEM method that one can use in alternative to the common property this[]: in this way debugging is easier (for examply by showing a holy MessageBox when accessing the values).
So, I pass the class instantiated in initCS to JScript, and JScript reads the internal Hashtable (HT). What I need to do is evaluate the data in the Hashtable, because it is supposed to be able to alter itself dynamically.
Everything works fine if I eval a string not taken from the Hashtable -- in the moment I take whatever is in the Hashtable and pass it to eval, then exceptions happen. Attention: the strings are absolutely the same (even comparing them with Equals) and they work, the difference is only from where they come from.
When the JScript function edata evals a string taken from the Hashtable, JScript says "index out of bounds", but as I was saying: I don't see any array there... (and maybe the problem is exactly that, dunno).
I admit I have my limitations in JScript, so if anybody could lend a hand to help understand WTF is going on, I would be really happy.

Upvotes: 0

Views: 172

Answers (1)

lunadir
lunadir

Reputation: 339

Temporary solution/workaround splitting the JScript function:

    xc=@"function odata(fieldname:String,ival:String):Object{
            var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
            var v1=sob.GetType().GetField(fieldname).GetValue(sob);

            return v1.ITEM(ival);
        }
        odata('HT','bar');";
    res=js_eval(xc);

    xc=@"function HASH(s1:String,s2:String):Object{
            var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
            var q1=sob.GetType().GetField(s1).GetValue(sob);
            return q1.ITEM(s2);
        }
        eval("+res.ToString()+");";
    res=js_eval(xc);

but if anybody really got any idea of why is wrong in the first example, please explain me!

Upvotes: 0

Related Questions