From 5d484144df8ce8d6cfb6b24f4f7f09de85bc564f Mon Sep 17 00:00:00 2001 From: drakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com> Date: Sun, 20 Dec 2020 14:41:11 -0500 Subject: [PATCH] Roslyn now outputs line/character info for syntax and runtime errors --- .../Tools/ErrorTool/medium.font.png | Bin 0 -> 2676 bytes .../WorkspaceTool/ProjectTemplate/code.cs | 39 +++++++++++++ .../WorkspaceTool/ProjectTemplate/code.lua | 2 +- PixelVision8.CoreDesktop.csproj | 5 ++ SDK/Runner/DesktopRunner.cs | 54 +++++++++++------- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 Content/PixelVisionOS/Tools/ErrorTool/medium.font.png create mode 100644 Disks/PixelVisionOS/System/Tools/WorkspaceTool/ProjectTemplate/code.cs diff --git a/Content/PixelVisionOS/Tools/ErrorTool/medium.font.png b/Content/PixelVisionOS/Tools/ErrorTool/medium.font.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9926a901a8da32fe24d043c0be2af875d0991b GIT binary patch literal 2676 zcmb7GdsGuw8jn^B#aFekRuAY9XsaG4^TQwnF#R1Gp`1eX+cYojSyWdSkM!ID})buEYLNURbY|4c974Uj7ay0yX^|!st;q57R@^X(tG47e* zHA+#t^;w1D$;+ZG%bS&!%JPy^#R-xfsQgYhv{oqQC;8nRzY=&6JIE7VdgTu-CzXgO z=#|UpG(6311o>iei42yMq}%wCl{_OTlNKQJ{VWXN1YQpDI}2PM)~{EF;7Xg<&}^%g)0%0w1<>7s>^pGzmNg3V;*F z^FU5Sn21RTRr$dPd0>EssFUcY-8m_=3@rA*VR+C-{XHh%znfRm^d%cD}%L*;_$1n;X0PkvLu1xS{5GyNRtH7 zQ5-g9Py$Cu+C~IxoK;gOPCYb*8%N;0-2XKec-A4wP7cLo9$3o=nR^#A-Hb2u7npNfi;?CWES)fGidPVUa93kx-qp;s`l* z@OGUB@M@IOs&SMebUM_|6ATpD?$8o;KoJ6`9P$?)sgJ=v0Y{)t50^}89fX$R?I>V4 z9;E;!pgKVVqiIO3hIbGShn-Pk;Uy-E9;jOJP;XcQRt-HBh!7EOE|%ki`yA5bAd}!S zf`cQ`;0c-|bPg@5;RQQNQ3Qu_G)KK}Pq(wtPLqo9d2Oq-+4txn8S-=HTCBp;hA9I+g3dIu( ztR{oazqLQ-lU1kj@t)EPr_`+%R&OfW*ip4$Ys&9qMok`{xpTL>_;!BH2eW<`h<|0$ zmh0q%6`#NC`(D1oUXH^J-^&v%Ez>TgB+_G(8V2^A=)?jC1KZYgCv`7;p)M}h{NU1^ zy65_QxgGBh;AML4=1*g(huE%N^077RqDlu zmW|ssO=XL%t$Vt|vguojss@pJCtIWEs9L{n-ZKd_u8vz5QHc99A~yd0fNOQ{-IP&x z&;PmcH{93riXYG$_nzLdx9O{QdyZD^S$lD6=UB3_bgDY)^)BmY#pm|Z9piG>``eD( zJh~yqh0xi*3S0r<;nN{I`$nTWqYc< z#$CcKj(#quhAP>#eNEIGXv{L*sf76ZA9r1w_w1$8hy+92=U2B^b!A(|CM~($H4waNxivr zSKJ|G&Xp!UFynT^l()(a(ewWE*8Jp)sgA~vdj=Y9UCQlu4z)DrrcPPcma=0EIZCzp zLd@%SZo=XGxO-Xcr}}oznp}Q_{A6y@+bT!u8OvFbo0yTj_lBXq& zOZC+^>YwP?fA*EN&-)X1ts7`tm-ylgs^Y!7U*4Oa#O|EFJ_Xy*)HE*TSPoB7(l&+abnR?+YLr8ptJdCivo`(`~9G3JXh%T;6H zgjb8&r=DE1vC$BD>)@ZVSMBPV86R1x^zA?2{z9e2+?{ml^uVn^$-bS{)8G8>Ny#3l z>AhST+jpaX`GIe<8!Eb;bxk*BUtjv^fqiA86R&=G?X_vy8-o7}t>$!7= 0; i--) + DrawText(lines[i], 1, startY + (i - 1), DrawMode.Tile, "large", 15); + } + + public override void Draw() + { + + } + + public override void Update(int timeDelta) + { + RedrawDisplay(); + } + } +} \ No newline at end of file diff --git a/Disks/PixelVisionOS/System/Tools/WorkspaceTool/ProjectTemplate/code.lua b/Disks/PixelVisionOS/System/Tools/WorkspaceTool/ProjectTemplate/code.lua index 6ec87040..f7de4874 100755 --- a/Disks/PixelVisionOS/System/Tools/WorkspaceTool/ProjectTemplate/code.lua +++ b/Disks/PixelVisionOS/System/Tools/WorkspaceTool/ProjectTemplate/code.lua @@ -16,7 +16,7 @@ of fonts into the default.font.png. Use uppercase for larger characters and lowercase for a smaller one. ]]-- -local message = "EMPTY GAME\n\n\nThis is an empty game template.\n\n\nVisit 'www.pixelvision8.com' to learn more about creating games from scratch." +local message = "EMPTY GAME\n\n\nThis is an empty Lua game template.\n\n\nVisit 'www.pixelvision8.com' to learn more about creating games from scratch." --[[ The Init() method is part of the game's lifecycle and called a game starts. diff --git a/PixelVision8.CoreDesktop.csproj b/PixelVision8.CoreDesktop.csproj index de2697fb..4c64be5e 100755 --- a/PixelVision8.CoreDesktop.csproj +++ b/PixelVision8.CoreDesktop.csproj @@ -38,6 +38,11 @@ + + + + + diff --git a/SDK/Runner/DesktopRunner.cs b/SDK/Runner/DesktopRunner.cs index bc0b4e4a..50eb8465 100755 --- a/SDK/Runner/DesktopRunner.cs +++ b/SDK/Runner/DesktopRunner.cs @@ -16,10 +16,13 @@ // Christer Kaitila - @McFunkypants // Pedro Medeiros - @saint11 // Shawn Rakowski - @shwany +// Drake Williams - drakewill+pv8@gmail.com // using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using MoonSharp.Interpreter; @@ -762,7 +765,7 @@ protected override void Update(GameTime gameTime) { DisplayError(ErrorCode.Exception, new Dictionary - {{"@{error}", e is ScriptRuntimeException error ? error.DecoratedMessage : e.Message}}, + {{"@{error}", e is ScriptRuntimeException error ? error.DecoratedMessage : e.Message + e.StackTrace.Split("\r\n")[0]}}, e); } } @@ -1557,27 +1560,28 @@ protected void ParseFiles(string[] files, SaveFlags? flags = null) loadService.ParseFiles(files, _tmpEngine, flags.Value); } - public void CompileFromSource(string[] files) + public void CompileFromSource(string[] files, bool buildDebugData = true) { var total = files.Length; - var syntaxTrees = new SyntaxTree[total]; + var embeddedTexts = new EmbeddedText[total]; - for (var i = 0; - i < total; - i++) + for (var i = 0; i < total; i++) { var path = WorkspacePath.Parse(files[i]); - var data = workspaceService.ReadTextFromFile(path); - syntaxTrees[i] = CSharpSyntaxTree.ParseText(data); + //if (buildDebugData) + //{ + var st = SourceText.From(text: data, encoding: Encoding.UTF8); //, canBeEmbedded: true isnt present when passing in a string? + embeddedTexts[i] = EmbeddedText.FromSource(files[i], st); + //} } //Compilation options, should line up 1:1 with Visual Studio since it's the same underlying compiler. var options = new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, - optimizationLevel: OptimizationLevel.Release, + optimizationLevel: buildDebugData ? OptimizationLevel.Debug : OptimizationLevel.Release, moduleName: "RoslynGame"); //All of these are mandatory. This appears to the be minimum needed. Uncertain as of initial PoC if anything else outside of this needs referenced. @@ -1598,41 +1602,47 @@ public void CompileFromSource(string[] files) var compiler = CSharpCompilation.Create("LoadedGame", syntaxTrees, references, options); //Compile the existing file into memory, or error out. - var stream = new MemoryStream(); + var dllStream = new MemoryStream(); + var pdbStream = new MemoryStream(); + + //This wont help unless we hit a runtime error. + var emitOptions = new EmitOptions( + debugInformationFormat: DebugInformationFormat.PortablePdb, + pdbFilePath: "RoslynGame.pdb" + ); - var compileResults = compiler.Emit(stream); + var compileResults = compiler.Emit( peStream: dllStream, pdbStream: pdbStream, embeddedTexts:embeddedTexts, options: emitOptions); if (compileResults.Success) { - stream.Seek(0, SeekOrigin.Begin); + dllStream.Seek(0, SeekOrigin.Begin); + pdbStream.Seek(0, SeekOrigin.Begin); } else { var errors = compileResults.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); - - // TODO Need to get the error from the compiler - // var e = "Code could not be compiled"; + var errorData = errors[0].Location.GetLineSpan(); + var lineNumber = errorData.StartLinePosition.Line + 1; + var charNumber = errorData.StartLinePosition.Character + 1; DisplayError(ErrorCode.Exception, new Dictionary { { "@{error}", errors.Count > 0 - ? errors[0].GetMessage() + ? "Line " + lineNumber + " Pos " + charNumber + ": " + errors[0].GetMessage() : "There was an unknown errror trying to compile a C# file." } }); - //TODO: error handling, use data from compileResults to show user what's wrong. return; } - //Get the DLL into active memory so we can use it. - var roslynassembly = stream.ToArray(); - var loadedAsm = Assembly.Load(roslynassembly); + //Get the DLL into active memory so we can use it. Runtime errors will give the wrong line number if we're in Release mode. + var loadedAsm = Assembly.Load(dllStream.ToArray(), buildDebugData ? pdbStream.ToArray() : null); var roslynGameChipType = - loadedAsm.GetType("PixelVisionRoslyn.RoslynGameChip"); //This type much match what's in code.cs. - //Could theoretically iterate over types until once that inherits from GameChip is found, but this Proof of Concept demonstrates the baseline feature. + loadedAsm.GetType("PixelVisionRoslyn.RoslynGameChip"); //code.cs must use this type. + //Could theoretically iterate over types until one that inherits from GameChip is found, but this strictness may be a better idea. if (roslynGameChipType != null) {