/// <summary> /// Run the Compiler. /// </summary> /// <param name="npfn">Fully qualified path to topmost file.</param> /// <returns>The newly minted script object or null if failed.</returns> public NpScript Execute(string npfn) { NpScript script = null; // Reset everything. _filesToCompile.Clear(); _initLines.Clear(); Errors.Clear(); if (File.Exists(npfn)) { _logger.Info($"Compiling {npfn}."); ///// Get and sanitize the script name. _scriptName = Path.GetFileNameWithoutExtension(npfn); StringBuilder sb = new StringBuilder(); _scriptName.ForEach(c => sb.Append(char.IsLetterOrDigit(c) ? c : '_')); _scriptName = sb.ToString(); _baseDir = Path.GetDirectoryName(npfn); ///// Compile. DateTime startTime = DateTime.Now; // for metrics Parse(npfn); script = Compile(); _logger.Info($"Compile took {(DateTime.Now - startTime).Milliseconds} msec."); } else { _logger.Error($"Invalid file {npfn}."); } return(Errors.Count == 0 ? script : null); }
/// <summary> /// Update per new script object. /// </summary> /// <param name="script"></param> public void InitSurface(NpScript script) { if (script != null) { _script = script; ClientSize = new System.Drawing.Size(_script.width, _script.height); _script.focused = Focused; _script.frameCount = 0; _script.setup(); } }
/// <summary> /// Top level compiler. /// </summary> /// <returns>Compiled script</returns> NpScript Compile() { NpScript script = null; try // many ways to go wrong... { // Set the compiler parameters. CompilerParameters cp = new CompilerParameters() { GenerateExecutable = false, //OutputAssembly = _scriptName, -- don't do this! GenerateInMemory = true, TreatWarningsAsErrors = false, IncludeDebugInformation = true }; // The usual suspects. cp.ReferencedAssemblies.Add("System.dll"); cp.ReferencedAssemblies.Add("System.Core.dll"); cp.ReferencedAssemblies.Add("System.Drawing.dll"); cp.ReferencedAssemblies.Add("System.Windows.Forms.dll"); cp.ReferencedAssemblies.Add("System.Data.dll"); cp.ReferencedAssemblies.Add("SkiaSharp.dll"); cp.ReferencedAssemblies.Add("NBagOfTricks.dll"); cp.ReferencedAssemblies.Add("NProcessing.Script.dll"); // Add the generated source files. List <string> paths = new List <string>(); // Create output area. TempDir = Path.Combine(_baseDir, "temp"); Directory.CreateDirectory(TempDir); Directory.GetFiles(TempDir).ForEach(f => File.Delete(f)); foreach (string genFn in _filesToCompile.Keys) { FileContext ci = _filesToCompile[genFn]; string fullpath = Path.Combine(TempDir, genFn); File.Delete(fullpath); File.WriteAllLines(fullpath, MiscUtils.FormatSourceCode(ci.CodeLines)); paths.Add(fullpath); } // Make it compile. CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerResults cr = provider.CompileAssemblyFromFile(cp, paths.ToArray()); if (cr.Errors.Count == 0) { Assembly assy = cr.CompiledAssembly; // Bind to the script interface. foreach (Type t in assy.GetTypes()) { if (t.BaseType != null && t.BaseType.Name == "NpScript") { // We have a good script file. Create the executable object. Object o = Activator.CreateInstance(t); script = o as NpScript; } } if (script == null) { throw new Exception("Could not instantiate script"); } } else { foreach (CompilerError err in cr.Errors) { // The line should end with source line number: "//1234" int origLineNum = 0; // defaults string origFileName = "???"; // Dig out the offending source code information. string fpath = Path.GetFileName(err.FileName.ToLower()); if (_filesToCompile.ContainsKey(fpath)) { FileContext ci = _filesToCompile[fpath]; origFileName = ci.SourceFile; string origLine = ci.CodeLines[err.Line - 1]; int ind = origLine.LastIndexOf("//"); if (origFileName == "" || ind == -1) { // Must be an internal error. Do the best we can. Errors.Add(new ScriptError() { ErrorType = err.IsWarning ? ScriptErrorType.Warning : ScriptErrorType.Error, SourceFile = err.FileName, LineNumber = err.Line, Message = $"InternalError: {err.ErrorText} in: {origLine}" }); } else { int.TryParse(origLine.Substring(ind + 2), out origLineNum); Errors.Add(new ScriptError() { ErrorType = err.IsWarning ? ScriptErrorType.Warning : ScriptErrorType.Error, SourceFile = origFileName, LineNumber = origLineNum, Message = err.ErrorText }); } } else { Errors.Add(new ScriptError() { ErrorType = err.IsWarning ? ScriptErrorType.Warning : ScriptErrorType.Error, SourceFile = "NoSourceFile", LineNumber = -1, Message = err.ErrorText }); } } } } catch (Exception ex) { Errors.Add(new ScriptError() { ErrorType = ScriptErrorType.Error, Message = "Exception: " + ex.Message, SourceFile = "", LineNumber = 0 }); } return(script); }