Skip to content

Commit 9672da1

Browse files
committed
添加 CoreCLR ILAsm
1 parent 15b9e45 commit 9672da1

14 files changed

Lines changed: 946 additions & 761 deletions
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using ILAssembler;
2+
using SharpScript.Models;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Collections.Immutable;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Reflection.Metadata;
9+
using System.Reflection.PortableExecutable;
10+
using System.Text;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
using Diagnostic = SharpScript.Models.Diagnostic;
14+
using ILDiagnostic = ILAssembler.Diagnostic;
15+
using RoslynSourceText = Microsoft.CodeAnalysis.Text.SourceText;
16+
17+
namespace SharpScript.Common
18+
{
19+
public sealed partial class CoreCLRCodeSession(RoslynSourceText code, Options options) : ICodeSession
20+
{
21+
RoslynSourceText ICodeSession.SourceCode => code;
22+
23+
public void ResetCode(string _code) => code = RoslynSourceText.From(_code, Encoding.Default);
24+
25+
public void ApplyChanges(params TextChanges[] changes)
26+
{
27+
foreach (TextChanges change in changes)
28+
{
29+
code = code.WithChanges(change);
30+
}
31+
}
32+
33+
public ValueTask<CompilationResults?> CompileAsync(ICollection<Diagnostic> results, CancellationToken cancellationToken = default)
34+
{
35+
cancellationToken.ThrowIfCancellationRequested();
36+
DocumentCompiler compiler = new();
37+
(ImmutableArray<ILDiagnostic> diagnostics, PEBuilder? builder) = compiler.Compile(
38+
code.AsSourceTest("Program.il"),
39+
path => new SourceText(string.Empty, path),
40+
_ => [],
41+
options);
42+
if (builder != null)
43+
{
44+
MemoryStream assemblyStream = new();
45+
BlobBuilder blobBuilder = new();
46+
builder.Serialize(blobBuilder);
47+
blobBuilder.WriteContentTo(assemblyStream);
48+
_ = assemblyStream.Seek(0, SeekOrigin.Begin);
49+
return ValueTask.FromResult<CompilationResults?>(new CompilationResults("SharpScript.Playground", assemblyStream, null));
50+
}
51+
results.AddRange(diagnostics.Select(x => new Diagnostic(x)));
52+
return ValueTask.FromResult<CompilationResults?>(null);
53+
}
54+
55+
public ValueTask<T> GetDiagnosticsAsync<T>(T results, CancellationToken cancellationToken = default) where T : ICollection<Diagnostic>
56+
{
57+
cancellationToken.ThrowIfCancellationRequested();
58+
DocumentCompiler compiler = new();
59+
(ImmutableArray<ILDiagnostic> diagnostics, PEBuilder? builder) = compiler.Compile(
60+
code.AsSourceTest("Program.il"),
61+
path => new SourceText(string.Empty, path),
62+
_ => [],
63+
options);
64+
results.AddRange(diagnostics.Select(x => new Diagnostic(x)));
65+
return ValueTask.FromResult(results);
66+
}
67+
}
68+
69+
file static class Extensions
70+
{
71+
public static SourceText AsSourceTest(this RoslynSourceText sourceText, string path) => new(sourceText.ToString(), path);
72+
}
73+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.Text;
3+
using Mobius.ILasm.Core;
4+
using SharpScript.Models;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Text;
9+
using System.Text.RegularExpressions;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Diagnostic = SharpScript.Models.Diagnostic;
13+
14+
namespace SharpScript.Common
15+
{
16+
public sealed partial class MonoCodeSession(SourceText code, bool isConsole) : ICodeSession
17+
{
18+
SourceText ICodeSession.SourceCode => code;
19+
20+
public void ResetCode(string _code) => code = SourceText.From(_code, Encoding.Default);
21+
22+
public void ApplyChanges(params TextChanges[] changes)
23+
{
24+
foreach (TextChanges change in changes)
25+
{
26+
code = code.WithChanges(change);
27+
}
28+
}
29+
30+
public ValueTask<CompilationResults?> CompileAsync(ICollection<Diagnostic> results, CancellationToken cancellationToken = default)
31+
{
32+
cancellationToken.ThrowIfCancellationRequested();
33+
Logger logger = new(results);
34+
Driver driver = new(logger, isConsole ? Driver.Target.Exe : Driver.Target.Dll, false, false, false);
35+
try
36+
{
37+
MemoryStream assemblyStream = new();
38+
if (driver.Assemble([code.ToString()], assemblyStream))
39+
{
40+
_ = assemblyStream.Seek(0, SeekOrigin.Begin);
41+
return ValueTask.FromResult<CompilationResults?>(new CompilationResults("SharpScript.Playground", assemblyStream, null));
42+
}
43+
}
44+
catch (Exception ex) when (ex.GetType().Name.StartsWith("yy"))
45+
{
46+
return ValueTask.FromResult<CompilationResults?>(null);
47+
}
48+
return ValueTask.FromResult<CompilationResults?>(null);
49+
}
50+
51+
public ValueTask<T> GetDiagnosticsAsync<T>(T results, CancellationToken cancellationToken = default) where T : ICollection<Diagnostic>
52+
{
53+
cancellationToken.ThrowIfCancellationRequested();
54+
Logger logger = new(results);
55+
Driver driver = new(logger, isConsole ? Driver.Target.Exe : Driver.Target.Dll, false, false, false);
56+
57+
try
58+
{
59+
using MemoryStream assemblyStream = new();
60+
_ = driver.Assemble([code.ToString()], assemblyStream);
61+
return ValueTask.FromResult(results);
62+
}
63+
catch (Exception ex) when (ex.GetType().Name.StartsWith("yy"))
64+
{
65+
return ValueTask.FromResult(results);
66+
}
67+
}
68+
69+
private partial class Logger(ICollection<Diagnostic> results) : Mobius.ILasm.interfaces.ILogger
70+
{
71+
public void Info(string message) => results.Add(new Diagnostic(DiagnosticSeverity.Info, message));
72+
73+
public void Warning(string message)
74+
{
75+
if (MissingReferenceRegex.Match(message) is { Success: true, Groups: [_, { Value: { Length: > 0 } value }] })
76+
{
77+
Task<IReadOnlyList<TextChange>?> InvokeAsync()
78+
{
79+
return Task.FromResult<IReadOnlyList<TextChange>?>([
80+
new TextChange(
81+
new TextSpan(0, 0),
82+
$$"""
83+
.assembly extern {{value}} {
84+
}
85+
86+
""")
87+
]);
88+
}
89+
ILCodeAction action = new("adding", InvokeAsync);
90+
results.Add(new Diagnostic(DiagnosticSeverity.Warning, message.Replace(", adding.", "."), action));
91+
}
92+
else
93+
{
94+
results.Add(new Diagnostic(DiagnosticSeverity.Warning, message));
95+
}
96+
}
97+
98+
public void Error(string message) => results.Add(new Diagnostic(DiagnosticSeverity.Error, message));
99+
100+
public void Warning(Mono.ILASM.Location location, string message) => results.Add(new Diagnostic(location, DiagnosticSeverity.Warning, message));
101+
102+
public void Error(Mono.ILASM.Location location, string message) => results.Add(new Diagnostic(location, DiagnosticSeverity.Error, message));
103+
104+
[GeneratedRegex(@"^Reference to undeclared extern assembly '(.*)', adding\.$")]
105+
private static partial Regex MissingReferenceRegex { get; }
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)