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); }
/// <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")); }