/// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads
        /// the class to the current AppDomain.
        /// <para>
        /// After initializing the class instance it is aligned to the interface specified by the parameter <c>T</c>.
        /// </para>
        /// </summary>
        /// <example>The following is the simple example of the interface alignment:
        /// <code>
        /// public interface ICalc
        /// {
        ///     int Sum(int a, int b);
        ///     int Div(int a, int b);
        /// }
        /// ....
        /// ICalc script = CSScript.CodeDomEvaluator
        ///                        .LoadMethod&lt;ICalc&gt;(@"public int Sum(int a, int b)
        ///                                             {
        ///                                                 return a + b;
        ///                                             }
        ///                                             public int Div(int a, int b)
        ///                                             {
        ///                                                 return a/b;
        ///                                             }");
        /// int result = script.Div(15, 3);
        /// </code>
        /// </example>
        /// <typeparam name="T">The type of the interface type the script class instance should be aligned to.</typeparam>
        /// <param name="code">The C# script text.</param>
        /// <returns>Aligned to the <c>T</c> interface instance of the auto-generated class defined in the script.</returns>
        public T LoadMethod <T>(string code) where T : class
        {
            string scriptText = CSScript.WrapMethodToAutoClass(code, false, false);

            return(LoadCode <T>(scriptText));
        }
 /// <summary>
 /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads
 /// the class to the current AppDomain.
 /// <para>Returns instance of <c>T</c> delegate for the first method in the auto-generated class.</para>
 /// </summary>
 ///  <example>
 /// <code>
 /// var Product = CSScript.CodeDomEvaluator
 ///                       .LoadDelegate&lt;Func&lt;int, int, int&gt;&gt;(
 ///                                   @"int Product(int a, int b)
 ///                                     {
 ///                                         return a * b;
 ///                                     }");
 ///
 /// int result = Product(3, 2);
 /// </code>
 /// </example>
 /// <param name="code">The C# code.</param>
 /// <returns>Instance of <c>T</c> delegate.</returns>
 public T LoadDelegate <T>(string code) where T : class
 {
     return(CSScript.LoadDelegate <T>(code));
 }
        /// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads
        /// the class to the current AppDomain.
        /// </summary>
        /// <example>The following is the simple example of the LoadMethod usage:
        /// <code>
        /// dynamic script = CSScript.CodeDomEvaluator
        ///                          .LoadMethod(@"int Product(int a, int b)
        ///                                        {
        ///                                            return a * b;
        ///                                        }");
        ///
        /// int result = script.Product(3, 2);
        /// </code>
        /// </example>
        /// <param name="code">The C# script text.</param>
        /// <returns>Instance of the first class defined in the script.</returns>
        public object LoadMethod(string code)
        {
            string scriptText = CSScript.WrapMethodToAutoClass(code, false, false);

            return(LoadCode(scriptText));
        }
        /// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>) and evaluates it.
        /// <para>
        /// This method is a logical equivalent of <see cref="CSScriptLibrary.IEvaluator.CompileCode"/> but is allows you to define
        /// your script class by specifying class method instead of whole class declaration.</para>
        /// </summary>
        /// <example>
        ///<code>
        /// dynamic script = CSScript.CodeDomEvaluator
        ///                          .CompileMethod(@"int Sum(int a, int b)
        ///                                           {
        ///                                               return a+b;
        ///                                           }")
        ///                          .CreateObject("*");
        ///
        /// var result = script.Sum(7, 3);
        /// </code>
        /// </example>
        /// <param name="code">The C# code.</param>
        /// <returns>The compiled assembly.</returns>
        public Assembly CompileMethod(string code)
        {
            string scriptText = CSScript.WrapMethodToAutoClass(code, false, false);

            return(CompileCode(scriptText));
        }
        /// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>), evaluates it and loads the class to the current AppDomain.
        /// <para>Returns typed <see cref="CSScriptLibrary.MethodDelegate{T}"/> for class-less style of invoking.</para>
        /// </summary>
        /// <typeparam name="T">The delegate return type.</typeparam>
        /// <example>
        /// <code>
        /// var product = CSScript.CodeDomEvaluator
        ///                       .CreateDelegate&lt;int&gt;(@"int Product(int a, int b)
        ///                                             {
        ///                                                 return a * b;
        ///                                             }");
        ///
        /// int result = product(3, 2);
        /// </code>
        /// </example>
        /// <param name="code">The C# code.</param>
        /// <returns> The instance of a typed <see cref="CSScriptLibrary.MethodDelegate{T}"/></returns>
        public MethodDelegate <T> CreateDelegate <T>(string code)
        {
            string scriptText = CSScript.WrapMethodToAutoClass(code, true, false);

            return(CompileCode(scriptText).GetStaticMethod <T>());
        }
 /// <summary>
 /// Evaluates (compiles) C# code (script). The C# code is a typical C# code containing a single or multiple class definition(s).
 /// </summary>
 /// <example>
 ///<code>
 /// Assembly asm = CSScript.CodeDomEvaluator
 ///                        .CompileCode(@"using System;
 ///                                       public class Script
 ///                                       {
 ///                                           public int Sum(int a, int b)
 ///                                           {
 ///                                               return a+b;
 ///                                           }
 ///                                       }");
 ///
 /// dynamic script =  asm.CreateObject("*");
 /// var result = script.Sum(7, 3);
 /// </code>
 /// </example>
 /// <param name="scriptText">The C# script text.</param>
 /// <returns>The compiled assembly.</returns>
 public Assembly CompileCode(string scriptText)
 {
     return(CSScript.LoadCode(scriptText, null, this.DebugBuild, this.referencedAssemblies.ToArray()));
 }
Пример #7
0
        Assembly CompileCode(string scriptText, string scriptFile)
        {
            string tempScriptFile = null;

            try
            {
                if (this.IsDebug)
                {
                    // Excellent example of debugging support
                    // http://www.michalkomorowski.com/2016/10/roslyn-how-to-create-custom-debuggable_27.html

                    if (scriptFile == null)
                    {
                        tempScriptFile = CSScript.GetScriptTempFile();
                        File.WriteAllText(tempScriptFile, scriptText, Encoding.UTF8);
                    }

                    scriptText = $"#line 1 \"{scriptFile ?? tempScriptFile}\"{Environment.NewLine}" + scriptText;
                }

                var options = CompilerSettings;
                if (!IsDebug)
                {
                    // There is a Roslyn bug that prevents emitting debug symbols if file path is specified. And fails
                    // the whole compilation:
                    // It triggers "error CS8055: Cannot emit debug information for a source text without encoding."
                    // Thus disable setting the source path until Roslyn is fixed.
                    options = CompilerSettings.WithFilePath(scriptFile ?? tempScriptFile);
                }

                var compilation = CSharpScript.Create(scriptText, options)
                                  .GetCompilation();

                if (this.IsDebug)
                {
                    compilation = compilation.WithOptions(compilation.Options
                                                          .WithOptimizationLevel(OptimizationLevel.Debug)
                                                          .WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
                }

                using (var pdb = new MemoryStream())
                    using (var asm = new MemoryStream())
                    {
                        var emitOptions = new EmitOptions(false, DebugInformationFormat.PortablePdb);

                        EmitResult result;
                        if (IsDebug)
                        {
                            result = compilation.Emit(asm, pdb, options: emitOptions);
                        }
                        else
                        {
                            result = compilation.Emit(asm);
                        }

                        if (!result.Success)
                        {
                            IEnumerable <Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError ||
                                                                                         d.Severity == DiagnosticSeverity.Error);

                            var message = new StringBuilder();
                            foreach (Diagnostic diagnostic in failures)
                            {
                                string error_location = "";
                                if (diagnostic.Location.IsInSource)
                                {
                                    var error_pos = diagnostic.Location.GetLineSpan().StartLinePosition;

                                    int error_line   = error_pos.Line + 1;
                                    int error_column = error_pos.Character + 1;

                                    // the actual source contains an injected '#line' directive f compiled with debug symbols
                                    if (IsDebug)
                                    {
                                        error_line--;
                                    }

                                    error_location = $"{diagnostic.Location.SourceTree.FilePath}({error_line},{ error_column}): ";
                                }
                                message.AppendLine($"{error_location}error {diagnostic.Id}: {diagnostic.GetMessage()}");
                            }
                            var errors = message.ToString();
                            throw new CompilerException(errors);
                        }
                        else
                        {
                            asm.Seek(0, SeekOrigin.Begin);
                            if (IsDebug)
                            {
                                pdb.Seek(0, SeekOrigin.Begin);
                                return(AppDomain.CurrentDomain.Load(asm.GetBuffer(), pdb.GetBuffer()));
                            }
                            else
                            {
                                return(AppDomain.CurrentDomain.Load(asm.GetBuffer()));
                            }
                        }
                    }
            }
            finally
            {
                if (this.IsDebug)
                {
                    CSScript.NoteTempFile(tempScriptFile);
                }
                else
                {
                    Utils.FileDelete(tempScriptFile, false);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>),
        /// evaluates it and loads the class to the remote AppDomain.
        /// <para>Returns non-typed <see cref="CSScriptLibrary.MethodDelegate"/> of the remote object for
        /// class-less style of invoking.</para>
        /// </summary>
        /// <example>
        /// <code>
        ///
        /// var log = CSScript.Evaluator
        ///                   .CreateDelegateRemotely(
        ///                                   @"void Log(string message)
        ///                                     {
        ///                                         Console.WriteLine(message);
        ///                                     }");
        ///
        /// log("Test message");
        ///
        /// log.UnloadOwnerDomain();
        /// </code>
        /// </example>
        /// <param name="evaluator">The evaluator.</param>
        /// <param name="code">The C# code.</param>
        /// <param name="probingDirs">The probing directories for the assemblies the script
        /// assembly depends on.</param>
        /// <returns> The instance of a 'duck typed' <see cref="CSScriptLibrary.MethodDelegate"/></returns>
        public static MethodDelegate CreateDelegateRemotely(this IEvaluator evaluator, string code, params string[] probingDirs)
        {
            string scriptCode = CSScript.WrapMethodToAutoClass(code, true, false, "MarshalByRefObject");

            var agentDef = @"
                             public class RemoteAgent : MarshalByRefObject, CSScriptLibrary.IRemoteAgent
                             {
                                 public object Method(params object[] parameters)
                                 {
                                      return Implementation(parameters);
                                 }
                                 public CSScriptLibrary.MethodDelegate Implementation {get; set;}
                             }";

            var cx = RemoteLoadingContext.NewFor(evaluator, scriptCode + agentDef);

            var remoteDomain = evaluator.GetRemoteDomain();

            if (remoteDomain == null)
            {
                remoteDomain = AppDomain.CurrentDomain.Clone();
            }

            remoteDomain.Execute(context =>
            {
                try
                {
                    IEvaluator eval = RemoteLoadingContext.CreateEvaluator(context);

                    var script = eval.ReferenceAssemblyOf <CSScript>()
                                 .CompileCode(context.code);

                    //var asm = script.GetType().Assembly.Location;

#if net45
                    string agentTypeName = script.DefinedTypes.Where(t => t.Name == "RemoteAgent").First().FullName;
#else
                    string agentTypeName = script.GetModules()
                                           .SelectMany(m => m.GetTypes())
                                           .Where(t => t.Name == "RemoteAgent")
                                           .First()
                                           .FullName;
#endif
                    var agent            = (IRemoteAgent)script.CreateObject(agentTypeName);
                    agent.Implementation = script.GetStaticMethod();
                    context.scriptObj    = agent;
                }
                catch (Exception e)
                {
                    context.error = e.ToString();
                }
            }, cx, probingDirs);

            if (cx.error != null)
            {
                throw new CompilerException("Exception in the remote AppDomain: " + cx.error);
            }

            var agentProxy = (IRemoteAgent)cx.scriptObj;

            MethodDelegate result = (param) => agentProxy.Method(param);

            evaluator.SetRemoteDomain(remoteDomain);
            result.SetOwnerDomain(remoteDomain)
            .SetOwnerObject(agentProxy);

            return(result);
        }
Пример #9
0
        /// <summary>
        /// Loads the method remotely.
        /// LoadMethodRemotely is essentially the same as <see cref="CSScriptLibrary.EvaluatorRemoting.LoadCodeRemotely{T}"/>.
        /// It just deals not with the whole class definition but a method(s) only. And the rest of the class definition is
        /// added automatically by CS-Script.
        /// </summary>
        /// <example>
        ///<code>
        /// var script = CSScript.Evaluator
        ///                      .LoadMethodRemotely&lt;ICalc&gt;(
        ///                                         @"public int Sum(int a, int b)
        ///                                           {
        ///                                               return a+b;
        ///                                           }
        ///                                           public int Sub(int a, int b)
        ///                                           {
        ///                                               return a-b;
        ///                                           }");
        ///
        /// int result = script.Sum(15, 3));
        ///
        /// // after the next line call the remote domain with loaded script will be unloaded
        /// script.UnloadOwnerDomain();
        /// </code>
        /// </example>
        /// <typeparam name="T">The type of the T.</typeparam>
        /// <param name="evaluator">The evaluator.</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public static T LoadMethodRemotely <T>(this IEvaluator evaluator, string code) where T : class
        {
            string scriptCode = CSScript.WrapMethodToAutoClass(code, false, false, "MarshalByRefObject, " + typeof(T));

            return(evaluator.LoadCodeRemotely <T>(scriptCode));
        }
Пример #10
0
        Assembly CompileCode(string scriptText, string scriptFile)
        {
            string tempScriptFile = null;

            try
            {
                if (this.IsDebug)
                {
                    if (scriptFile == null)
                    {
                        tempScriptFile = CSScript.GetScriptTempFile();
                        File.WriteAllText(tempScriptFile, scriptText);
                    }

                    scriptText = $"#line 1 \"{scriptFile ?? tempScriptFile}\"{Environment.NewLine}" + scriptText;
                }

                var compilation = CSharpScript.Create(scriptText, CompilerSettings
                                                      .WithFilePath(scriptFile ?? tempScriptFile))
                                  .GetCompilation();

                if (this.IsDebug)
                {
                    compilation = compilation.WithOptions(compilation.Options
                                                          .WithOptimizationLevel(OptimizationLevel.Debug)
                                                          .WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
                }

                using (var pdb = new MemoryStream())
                    using (var asm = new MemoryStream())
                    {
                        var emitOptions = new EmitOptions(false, DebugInformationFormat.PortablePdb);

                        EmitResult result;
                        if (IsDebug)
                        {
                            result = compilation.Emit(asm, pdb, options: emitOptions);
                        }
                        else
                        {
                            result = compilation.Emit(asm);
                        }

                        if (!result.Success)
                        {
                            IEnumerable <Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError ||
                                                                                         d.Severity == DiagnosticSeverity.Error);

                            var message = new StringBuilder();
                            foreach (Diagnostic diagnostic in failures)
                            {
                                string error_location = "";
                                if (diagnostic.Location.IsInSource)
                                {
                                    var error_pos = diagnostic.Location.GetLineSpan().StartLinePosition;

                                    int error_line   = error_pos.Line + 1;
                                    int error_column = error_pos.Character + 1;

                                    // the actual source contains an injected '#line' directive f compiled with debug symbols
                                    if (IsDebug)
                                    {
                                        error_line--;
                                    }

                                    error_location = $"{diagnostic.Location.SourceTree.FilePath}({error_line},{ error_column}): ";
                                }
                                message.AppendLine($"{error_location}error {diagnostic.Id}: {diagnostic.GetMessage()}");
                            }
                            var errors = message.ToString();
                            throw new CompilerException(errors);
                        }
                        else
                        {
                            asm.Seek(0, SeekOrigin.Begin);
                            if (IsDebug)
                            {
                                pdb.Seek(0, SeekOrigin.Begin);
                                return(AppDomain.CurrentDomain.Load(asm.GetBuffer(), pdb.GetBuffer()));
                            }
                            else
                            {
                                return(AppDomain.CurrentDomain.Load(asm.GetBuffer()));
                            }
                        }
                    }
            }
            finally
            {
                if (this.IsDebug)
                {
                    CSScript.NoteTempFile(tempScriptFile);
                }
                else
                {
                    Utils.FileDelete(tempScriptFile, false);
                }
            }
        }