public void ClassicModeTest()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
                CompilerMode      = ScriptCompilerModes.Classic
            };

            script.AddDefaultReferencesAndNamespaces();

            //script.AddAssembly("Westwind.Utilities.dll");
            //script.AddNamespace("Westwind.Utilities");

            var code = $@"
public string Add(int num1, int num2)
{{
    // string templates
    var result = num1 + "" + "" + num2 + "" =  "" + (num1 + num2);
    Console.WriteLine(result);

    return result;
}}
";

            string result = script.ExecuteMethod(code, "Add", 10, 5) as string;

            Console.WriteLine("Result: " + result);
            Assert.IsFalse(script.Error, script.ErrorMessage);
        }
        /// <summary>
        /// Evaluates the embedded script parsing out {{ C# Expression }}
        /// blocks and evaluating the expressions and embedding the string
        /// output into the result string.
        ///
        ///
        /// </summary>
        /// <param name="code">The code to execute
        /// <param name="model">Optional model data accessible in Expressions as `Model`</param>
        /// <returns></returns>
        public async Task <bool> EvaluateScriptAsync(string code, CommanderAddinModel model = null)
        {
            ScriptInstance = CreateScriptObject();

            string oldPath = Environment.CurrentDirectory;

            code = "public async Task<string> ExecuteScript(CommanderAddinModel Model)\n" +
                   "{\n" +
                   code + "\n" +
                   "return \"ok\";\n" +
                   "}";

            string res = await ScriptInstance.ExecuteMethodAsync <string>(code, "ExecuteScript", model);

            Directory.SetCurrentDirectory(oldPath);


            if (ScriptInstance.Error)
            {
                // fix error offsets so they match just the script code
                FixupLineNumbersAndErrors(ScriptInstance);
                ErrorMessage = ScriptInstance.ErrorMessage;
            }

            return(!ScriptInstance.Error);
        }
        public void ExecuteMethodTest()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
                CompilerMode      = ScriptCompilerModes.Roslyn
            };

            script.AddDefaultReferencesAndNamespaces();

            string code = $@"
public string HelloWorld(string name)
{{
    string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
    return result;
}}";

            string result = script.ExecuteMethod(code, "HelloWorld", "Rick") as string;

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);
            Console.WriteLine(script.GeneratedClassCode);

            Assert.IsFalse(script.Error);
            Assert.IsTrue(result.Contains("Hello Rick"));

            // Just invoke the method again directly without any compilation/building
            // this is the fastest way to do multiple invocations.
            result = script.InvokeMethod(script.ObjectInstance, "HelloWorld", "Markus") as string;

            Console.WriteLine($"Result: {result}");
            Assert.IsFalse(script.Error);
            Assert.IsTrue(result.Contains("Hello Markus"));
        }
        public void CompileClassTest()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
                CompilerMode      = ScriptCompilerModes.Roslyn
            };

            script.AddDefaultReferencesAndNamespaces();

            var code = $@"
using System;

namespace MyApp
{{
    public class Math
    {{
        public string Add(int num1, int num2)
        {{
            // string templates
            var result = num1 + "" + "" + num2 + "" = "" + (num1 + num2);
            Console.WriteLine(result);

            return result;
        }}

        public string Multiply(int num1, int num2)
        {{
           // string templates
            var result = $""{{num1}}  *  {{num2}} = {{ num1 * num2 }}"";
            Console.WriteLine(result);

            result = $""Take two: {{ result ?? ""No Result"" }}"";
            Console.WriteLine(result);

            return result;
        }}
    }}
}}
";

            dynamic math = script.CompileClass(code);

            Console.WriteLine(script.GeneratedClassCodeWithLineNumbers);

            Assert.IsFalse(script.Error, script.ErrorMessage);

            Assert.IsNotNull(math);

            string addResult   = math.Add(10, 20);
            string multiResult = math.Multiply(3, 7);


            Assert.IsTrue(addResult.Contains(" = 30"));
            Assert.IsTrue(multiResult.Contains(" = 21"));
        }
        public void ExecuteMoreThanOneMethodTest()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
                CompilerMode      = ScriptCompilerModes.Roslyn
            };

            script.AddDefaultReferencesAndNamespaces();

            string code = $@"
public string HelloWorld(string name)
{{
string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
return result;
}}

public string GoodbyeName {{ get; set; }}

public string GoodbyeWorld()
{{
string result = $""Goodbye {{GoodbyeName}}. Time is: {{DateTime.Now}}."";
return result;
}}
";

            string result = script.ExecuteMethod(code, "HelloWorld", "Rick") as string;

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);
            Console.WriteLine(script.GeneratedClassCode);

            Assert.IsFalse(script.Error);
            Assert.IsTrue(result.Contains("Hello Rick"));

            dynamic instance = script.ObjectInstance;

            instance.GoodbyeName = "Markus";
            result = instance.GoodbyeWorld();



            Console.WriteLine($"Result: {result}");
            Assert.IsTrue(result.Contains("Goodbye Markus"));
        }
        public void ExecuteCodeSnippetWithoutResult()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
            };

            script.AddDefaultReferencesAndNamespaces();

            string result =
                script.ExecuteCode("Console.WriteLine($\"Time is: {DateTime.Now}\");", null) as string;

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);
            Console.WriteLine(script.GeneratedClassCode);

            Assert.IsFalse(script.Error, script.ErrorMessage);
        }
        /// <summary>
        /// Creates an instance of wwScripting for this parser
        /// with the appropriate assemblies and namespaces set
        /// </summary>
        /// <returns></returns>
        private CSharpScriptExecution CreateScriptObject()
        {
            var scripting = new CSharpScriptExecution
            {
                GeneratedNamespace    = "MarkdownMonster.Commander.Scripting",
                ThrowExceptions       = false,
                AllowReferencesInCode = true
            };

            // Use loaded references so **all of MM is available**
            scripting.AddLoadedReferences();
            //.AddDefaultReferencesAndNamespaces();

            scripting.AddAssembly(typeof(CommanderAddin));


            scripting.AddNamespaces("System",
                                    "System.Threading.Tasks",
                                    "System.IO",
                                    "System.Reflection",
                                    "System.Text",
                                    "System.Drawing",
                                    "System.Diagnostics",
                                    "System.Data",
                                    "System.Data.SqlClient",
                                    "System.Linq",
                                    "System.Windows",
                                    "System.Windows.Controls",
                                    "System.Collections.Generic",

                                    "Newtonsoft.Json",
                                    "Newtonsoft.Json.Linq",

                                    "MarkdownMonster",
                                    "MarkdownMonster.Windows",
                                    "Westwind.Utilities",
                                    "CommanderAddin");

            scripting.SaveGeneratedCode = true;

            return(scripting);
        }
        public void EvaluateTest()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode = true,
            };

            script.AddDefaultReferencesAndNamespaces();

            // Full syntax
            //object result = script.Evaluate("(decimal) parameters[0] + (decimal) parameters[1]", 10M, 20M);

            // Numbered parameter syntax is easier
            object result = script.Evaluate("(decimal) @0 + (decimal) @1", 10M, 20M);

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);
            Console.WriteLine(script.GeneratedClassCode);

            Assert.IsFalse(script.Error, script.ErrorMessage);
            Assert.IsTrue(result is decimal, script.ErrorMessage);
        }
Exemple #9
0
        /// <summary>
        /// Evaluates the embedded script parsing out {{ C# Expression }}
        /// blocks and evaluating the expressions and embedding the string
        /// output into the result string.
        ///
        ///
        /// </summary>
        /// <param name="snippet">The snippet template to expand</param>
        /// <param name="model">Optional model data accessible in Expressions as `Model`</param>
        /// <returns></returns>
        public string EvaluateScript(string snippet, object model = null)
        {
#if DEBUG
            var sw = new Stopwatch();
            sw.Start();
#endif
            var tokens = TokenizeString(ref snippet, "{{", "}}");

            snippet = snippet.Replace("\"", "\"\"");

            snippet = DetokenizeString(snippet, tokens);

            snippet = snippet.Replace("{{", "\" + ").Replace("}}", " + @\"");
            snippet = "@\"" + snippet + "\"";


            string code = "dynamic Model = parameters[0];\r\n" +
                          "return " + snippet + ";";

            //var scriptCompiler = new ScriptRunnerRoslyn();
            var scriptCompiler = new CSharpScriptExecution()
            {
                CompilerMode = ScriptCompilerModes.Roslyn
            };
            scriptCompiler.AddDefaultReferencesAndNamespaces();

            scriptCompiler.AddAssemblies("System.dll",
                                         "System.Core.dll",
                                         "System.Drawing.dll",
                                         "Microsoft.CSharp.dll",
                                         "System.Data.dll",
                                         "MarkdownMonster.exe",
                                         "Westwind.Utilities.dll",
                                         "System.Configuration.dll",
                                         "Newtonsoft.Json.dll");

            scriptCompiler.AddNamespaces("System",
                                         "System.IO",
                                         "System.Reflection",
                                         "System.Text",
                                         "System.Drawing",
                                         "System.Diagnostics",
                                         "System.Data",
                                         "System.Data.SqlClient",
                                         "System.Linq",
                                         "System.Collections.Generic",
                                         "Newtonsoft.Json",
                                         "Newtonsoft.Json.Linq",
                                         "MarkdownMonster",
                                         "Westwind.Utilities");

            string result = scriptCompiler.ExecuteCode(code, model) as string;

            if (result == null)
            {
                ErrorMessage = scriptCompiler.ErrorMessage;
            }
            else
            {
                ErrorMessage = null;
            }

#if DEBUG
            sw.Stop();
            Debug.WriteLine("ScriptParser Code: \r\n" + code);
            Debug.WriteLine("Snippet EvaluateScript Execution Time: " + sw.ElapsedMilliseconds + "ms");
#endif

            return(result);
        }
        public static AdjustCodeLineNumberStatus FixupLineNumbersAndErrors(CSharpScriptExecution script)
        {
            var adjusted = new AdjustCodeLineNumberStatus();

            var code = script.GeneratedClassCode;

            var find  = "public async Task<string> ExecuteScript(CommanderAddinModel Model)";
            var lines = StringUtils.GetLines(code);
            int i     = 0;

            for (i = 0; i < lines.Length; i++)
            {
                if (lines[i]?.Trim() == find)
                {
                    break;
                }
            }

            if (i < lines.Length - 1)
            {
                adjusted.startLineNumber = i + 2;
            }

            // `(24,1): error CS0246: The type or namespace name...`
            lines = StringUtils.GetLines(script.ErrorMessage);
            for (i = 0; i < lines.Length; i++)
            {
                var line = lines[i];
                if (string.IsNullOrEmpty(line))
                {
                    continue;
                }

                var linePair = StringUtils.ExtractString(line, "(", "):", returnDelimiters: true);
                if (!linePair.Contains(","))
                {
                    continue;
                }

                var tokens = linePair.Split(',');

                var lineNo = StringUtils.ParseInt(tokens[0].Substring(1), 0);
                if (lineNo < adjusted.startLineNumber)
                {
                    continue;
                }

                // update the line number
                var newError = "(" + (lineNo - adjusted.startLineNumber) + "," + tokens[1] + line.Replace(linePair, "");
                lines[i] = newError;
            }

            var updatedLines = string.Empty;

            foreach (var line in lines)
            {
                updatedLines = updatedLines + line + "\n";
            }

            string.Join(",", lines);
            adjusted.UpdatedErrorMessage = updatedLines.Trim();

            return(adjusted);
        }
        public void ExecuteCodeSnippetWithResult()
        {
            var script = new CSharpScriptExecution()
            {
                SaveGeneratedCode  = true,
                CompilerMode       = ScriptCompilerModes.Roslyn,
                GeneratedNamespace = "ScriptExecutionTesting",
                GeneratedClassName = "MyTest"
            };

            script.AddDefaultReferencesAndNamespaces();

//script.AddAssembly("Westwind.Utilities.dll");
//script.AddNamespace("Westwind.Utilities");

            var code = $@"
// Check some C# 6+ lang features
var s = new {{ name = ""Rick""}}; // anonymous types
Console.WriteLine(s?.name);       // null propagation

int num1 = (int)parameters[0];
int num2 = (int)parameters[1];

// string templates
var result = $""{{num1}} + {{num2}} = {{(num1 + num2)}}"";
Console.WriteLine(result);

return result;
";

            string result = script.ExecuteCode(code, 10, 20) as string;

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);
            Console.WriteLine(script.GeneratedClassCodeWithLineNumbers);

            Assert.IsFalse(script.Error, script.ErrorMessage);
            Assert.IsTrue(result.Contains(" = 30"));

            result = script.ExecuteCode(code, 15, 10) as string;

            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);


            Assert.IsFalse(script.Error, script.ErrorMessage);
            Assert.IsTrue(result.Contains(" = 25"));

            script = new CSharpScriptExecution()
            {
                SaveGeneratedCode  = true,
                GeneratedClassName = "MyTest"
            };
            script.AddDefaultReferencesAndNamespaces();

            result = script.ExecuteCode(code, 4, 10) as string;
            Console.WriteLine($"Result: {result}");
            Console.WriteLine($"Error: {script.Error}");
            Console.WriteLine(script.ErrorMessage);


            Assert.IsFalse(script.Error, script.ErrorMessage);
            Assert.IsTrue(result.Contains(" = 14"));
        }