aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs
diff options
context:
space:
mode:
authorVictoria Plitt <Victoria.Plitt@twine-s.com>2019-04-08 13:49:55 +0300
committerVictoria Plitt <Victoria.Plitt@twine-s.com>2019-04-08 13:49:55 +0300
commitfc8a05358a92cc3c77c5f1e30d536807ef0614fd (patch)
treec65f696ebd60f3790145721307c255e5a339923f /Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs
parentb4a71931ea52636c6b36376aa9d71697ccf73524 (diff)
downloadTango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.tar.gz
Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.zip
were added scripting projects
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs')
-rw-r--r--Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs268
1 files changed, 268 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs
new file mode 100644
index 000000000..b3f5348f8
--- /dev/null
+++ b/Software/Visual_Studio/Scripting/Tango.Scripting/ScriptingEngine.cs
@@ -0,0 +1,268 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Tango.Scripting
+{
+ public class ScriptingEngine : IScriptingEngine
+ {
+ private class IncludeResult
+ {
+ public String File { get; set; }
+ public List<String> Lines { get; set; }
+ }
+
+ public Task<String> Compile(Script script)
+ {
+ return Task.Factory.StartNew<String>(() =>
+ {
+ String code = script.Code;
+ List<IncludeResult> includeResults = new List<IncludeResult>();
+
+ try
+ {
+ includeResults.Add(new IncludeResult() { File = script.File, Lines = script.Code.ToLines() });
+ code = ReplaceIncludes(script, code, script.WorkingFolder, includeResults);
+ }
+ catch (Exception ex)
+ {
+ throw new CompilationException(new CompilationError() { Message = ex.Message });
+ }
+
+ var options = CreateOptions(script);
+
+ var csharpScript = CSharpScript.Create(code, options: options, globalsType: script.GlobalObject.GetType());
+
+ var results = csharpScript.Compile();
+
+ List<CompilationError> errors = new List<CompilationError>();
+
+ foreach (var result in results.Where(x => x.Severity == DiagnosticSeverity.Error))
+ {
+ CompilationError error = new CompilationError();
+ error.Message = result.GetMessage();
+ error.Character = result.Location.GetMappedLineSpan().StartLinePosition.Character + 1;
+
+ int lineIndex = 0;
+ IncludeResult include = null;
+
+ foreach (var inc in includeResults)
+ {
+ for (int i = 0; i < inc.Lines.Count; i++)
+ {
+ if (inc.Lines[i] == code.ToLines()[result.Location.GetMappedLineSpan().StartLinePosition.Line])
+ {
+ include = inc;
+ lineIndex = i;
+ break;
+ }
+ }
+ }
+
+ if (include != null)
+ {
+ error.File = include.File;
+ error.Line = lineIndex + 1;
+ }
+
+ errors.Add(error);
+ }
+
+ if (errors.Count > 0)
+ {
+ throw new CompilationException(errors.ToArray());
+ }
+
+ return code;
+ });
+ }
+
+ public Task<ScriptSession> Run(Script script)
+ {
+ return Task.Factory.StartNew<ScriptSession>(() =>
+ {
+ var effectivCode = Compile(script).Result;
+
+ var options = CreateOptions(script);
+
+ var _cancaller = new CancellationTokenSource();
+
+ Thread scriptThread = null;
+ ScriptSession session = null;
+
+ session = new ScriptSession(script, effectivCode, () =>
+ {
+ scriptThread.Abort();
+ });
+
+ scriptThread = new Thread(() =>
+ {
+ try
+ {
+ var result = CSharpScript.RunAsync(effectivCode, options: options, globals: script.GlobalObject, cancellationToken: _cancaller.Token).Result;
+ session.Completed(result.ReturnValue);
+ }
+ catch (ThreadAbortException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ session.Failed(ex.InnerException);
+ }
+ });
+
+ scriptThread.SetApartmentState(script.ApartmentState);
+ scriptThread.IsBackground = true;
+ scriptThread.Start();
+
+ return session;
+ });
+ }
+
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+
+ #region Private Methods
+
+ private List<String> GetIncludes(String code, String workingFolder)
+ {
+ if (Directory.Exists(workingFolder))
+ {
+ Environment.CurrentDirectory = workingFolder;
+ }
+
+ List<String> lines = code.ToLines();
+ List<String> includeFiles = new List<string>();
+
+ for (int i = 0; i < lines.Count; i++)
+ {
+ var line = lines[i];
+
+ if (line.Trim().StartsWith("include"))
+ {
+ String path = line.Replace("include", "").Trim().Replace("\"", "");
+
+ if (!File.Exists(path))
+ {
+ throw new FileNotFoundException("Could not locate include file '" + path + "'.");
+ }
+
+ includeFiles.Add(path);
+ }
+ }
+
+ return includeFiles;
+ }
+
+ private String ReplaceIncludes(Script script, String code, String workingFolder, List<IncludeResult> includeResults)
+ {
+ if (Directory.Exists(workingFolder))
+ {
+ Environment.CurrentDirectory = workingFolder;
+ }
+
+ List<String> lines = code.ToLines().ToList();
+
+ for (int i = 0; i < lines.Count; i++)
+ {
+ var line = lines[i];
+
+ if (line.Trim().StartsWith("include"))
+ {
+ String path = line.Replace("include", "").Trim().Replace("\"", "");
+
+ if (!File.Exists(path))
+ {
+ throw new FileNotFoundException("Could not locate include file '" + path + "'.");
+ }
+
+ String includeContent = File.ReadAllText(path);
+
+ includeResults.Add(new IncludeResult() { File = path, Lines = includeContent.ToLines() });
+
+ String content = ReplaceIncludes(script, includeContent, Path.GetDirectoryName(path), includeResults);
+
+ if (!String.IsNullOrWhiteSpace(script.EntryPoint))
+ {
+ if (content.Contains(script.EntryPoint + "("))
+ {
+ throw new InvalidProgramException(String.Format("Include file '{0}' contains an OnExecute method. Please remove it before trying to compile.", path));
+ }
+ }
+
+ lines[i] = content;
+ }
+ }
+
+ code = ClearUsings(String.Join(Environment.NewLine, lines));
+
+ return code;
+ }
+
+ private String ClearUsings(String code)
+ {
+ List<String> usings = new List<string>();
+
+ List<String> lines = code.ToLines();
+
+ foreach (var line in lines)
+ {
+ if (line.Trim().StartsWith("using"))
+ {
+ usings.Add(line);
+ }
+ }
+
+ lines.RemoveAll(x => x.Trim().StartsWith("using"));
+
+ return String.Join(Environment.NewLine, usings.Distinct()) + Environment.NewLine + String.Join(Environment.NewLine, lines);
+ }
+
+ private ScriptOptions CreateOptions(Script script)
+ {
+ //My References.
+ var options = ScriptOptions.Default;
+
+ //My Assemblies.
+ options = options.AddReferences(typeof(Form).Assembly.Location);
+ options = options.AddReferences(typeof(Enumerable).Assembly.Location);
+ options = options.AddReferences(typeof(ScriptingEngine).Assembly.Location);
+
+ foreach (var asm in script.ReferenceAssemblies)
+ {
+ options = options.AddReferences(asm.File);
+ }
+
+ //Imports.
+ options = options.AddImports(
+ "System",
+ "System.Collections.Generic",
+ "System.Linq",
+ "System.Text",
+ "System.Diagnostics",
+ "System.Windows.Forms",
+ "System.Threading"
+ );
+
+ if (script.Imports.Count > 0)
+ {
+ options = options.AddImports(script.Imports);
+ }
+
+ return options;
+ }
+
+ #endregion
+ }
+}