diff options
| author | Shlomo Hecht <shlomo@twine-s.com> | 2020-04-21 16:04:12 +0300 |
|---|---|---|
| committer | Shlomo Hecht <shlomo@twine-s.com> | 2020-04-21 16:04:12 +0300 |
| commit | 78430d37ac1dd07d5b5d731698da6761884d4cd5 (patch) | |
| tree | ac46b2870e21e3ddbc7a7d0732340a93e4e774e2 /Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs | |
| parent | bd2e83f3d46414d756f59c2f70cc561718a3022e (diff) | |
| parent | 97a784b6ce43960bdb92465b08f26d3562a4f202 (diff) | |
| download | Tango-78430d37ac1dd07d5b5d731698da6761884d4cd5.tar.gz Tango-78430d37ac1dd07d5b5d731698da6761884d4cd5.zip | |
Merge branch 'master' of https://twinetfs.visualstudio.com/Tango/_git/Tango
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs')
| -rw-r--r-- | Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs new file mode 100644 index 000000000..31be3a714 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs @@ -0,0 +1,218 @@ +using Microsoft.CodeAnalysis.CSharp.Scripting; +using Microsoft.CodeAnalysis.Scripting; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Tango.Core; +using Tango.Core.IO; +using Tango.Scripting.Core; +using System.IO; + +namespace Tango.Scripting.Basic +{ + public class Project : ExtendedObject + { + private String _name; + public String Name + { + get { return _name; } + set { _name = value; RaisePropertyChangedAuto(); } + } + + private String _description; + public String Description + { + get { return _description; } + set { _description = value; RaisePropertyChangedAuto(); } + } + + public ApartmentState ApartmentState { get; set; } + + public ObservableCollection<ReferenceAssembly> ReferenceAssemblies { get; set; } + + [JsonIgnore] + public ObservableCollection<Assembly> ReferenceAssembliesLoaded { get; set; } + + public ObservableCollection<Script> Scripts { get; set; } + + public ObservableCollection<IScriptSource> AdditionalScripts + { + get + { + return Scripts.Where(x => !x.IsEntryPoint).Cast<IScriptSource>().ToObservableCollection(); + } + } + + public Project() + { + ApartmentState = ApartmentState.MTA; + + ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); + ReferenceAssemblies.CollectionChanged += ReferenceAssemblies_CollectionChanged; + + ReferenceAssembliesLoaded = new ObservableCollection<Assembly>(); + Scripts = new ObservableCollection<Script>(); + Scripts.CollectionChanged += (x, e) => { RaisePropertyChanged(nameof(AdditionalScripts)); }; + } + + private void ReferenceAssemblies_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + LoadReferenceAssemblies(); + } + + private void LoadReferenceAssemblies() + { + ReferenceAssembliesLoaded.Clear(); + + foreach (var type in ReferenceAssemblies) + { + ReferenceAssembliesLoaded.Add(type.FromType.Assembly); + } + } + + public static Project New(String name) + { + Project p = new Project(); + + p.Name = name; + + p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(String) }); + p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Enumerable) }); + p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Form) }); + p.ReferenceAssemblies.Add(new ReferenceAssembly() { FromType = typeof(Project) }); + return p; + } + + public Task<CompilationResult> Compile() + { + return Task.Factory.StartNew<CompilationResult>(() => + { + var result = new CompilationResult(); + var tempFolder = TemporaryManager.CreateFolder(Name); + result.TemporaryProjectPath = tempFolder; + + String mainScriptCode = String.Empty; + + foreach (var script in Scripts) + { + script.LoadCount = 0; + String code = script.Code; + String codeFile = Path.Combine(tempFolder, script.Name); + + String loadingString = String.Empty; + + foreach (var file in Scripts.Where(x => !x.IsEntryPoint && script != x).Select(x => Path.Combine(tempFolder, x.Name))) + { + loadingString = $"#load \"{file}\"\n"; + script.LoadCount++; + } + + code = loadingString + code; + + if (!script.IsEntryPoint) + { + //In case we use #load + //foreach (var match in Regex.Matches(code, "#load \".+\"").OfType<Match>()) + //{ + // String line = match.ToString(); + // var pathMatch = Regex.Match(line, "(?<=\")(.*?)(?=\")"); + // if (pathMatch.Success) + // { + // String path = pathMatch.ToString(); + + // if (!System.IO.Path.IsPathRooted(path)) + // { + // StringBuilder builder = new StringBuilder(code); + // builder.Insert(match.Index + pathMatch.Index, System.IO.Path.GetFullPath(tempFolder + "\\")); + // code = builder.ToString(); + // } + // } + //} + File.WriteAllText(codeFile, code); + } + else + { + code += Environment.NewLine + Environment.NewLine + "return new Program().OnExecute(GlobalContext);"; + mainScriptCode = code; + } + } + + var scriptOptions = ScriptOptions.Default.WithReferences(ReferenceAssembliesLoaded); + + var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject)); + result.Script = s; + + var compileResults = s.Compile(); + + foreach (var error in compileResults.Where(x => x.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error)) + { + CompilationError cError = new CompilationError(); + cError.File = System.IO.Path.GetFileName(error.Location.SourceTree.FilePath); + if (cError.File == String.Empty) + { + cError.File = Scripts.Single(x => x.IsEntryPoint).Name; + } + Script errorScript = Scripts.Single(x => x.Name == cError.File); + cError.Message = error.GetMessage(); + cError.Severity = error.Severity; + var line = error.Location.GetMappedLineSpan(); + cError.Line = line.StartLinePosition.Line + 1 + (errorScript != null ? errorScript.LoadCount : 0); + cError.Column = line.StartLinePosition.Character + 1; + cError.Length = line.EndLinePosition.Character - line.StartLinePosition.Character; + result.Errors.Add(cError); + } + + return result; + }); + } + + public async Task<ProjectSession> Run(IContext context) + { + var result = await Compile(); + + if (result.Errors.Count > 0) + { + throw new InvalidOperationException($"Cannot run project with the following compilation errors:\n{String.Join(Environment.NewLine, result.Errors.Select(x => x.Message))}"); + } + + Thread scriptThread = null; + ProjectSession session = null; + + session = new ProjectSession(this, () => + { + scriptThread.Abort(); + }); + + scriptThread = new Thread(() => + { + try + { + var runResult = result.Script.RunAsync(globals: new GlobalObject() { GlobalContext = context }).Result; + session.Completed(runResult.ReturnValue); + } + catch (ThreadAbortException) + { + + } + catch (Exception ex) + { + session.Failed(ex.InnerException); + } + }); + + scriptThread.SetApartmentState(ApartmentState); + scriptThread.IsBackground = true; + scriptThread.Start(); + + return session; + } + } +} |
