From d6ef2b5e76f7bd364e804f4cd1e7dd47d278290f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E6=9C=A8=E6=A3=AE=20=C2=B7=20=E4=BD=9C=E9=9C=96?=
<16236903+NMSAzulX@users.noreply.github.com>
Date: Tue, 2 Jul 2024 12:21:35 +0800
Subject: [PATCH] =?UTF-8?q?udpate=20compiler=20=E5=88=86=E7=A6=BB=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=81=A5=E5=A3=AE=E7=A8=8B=E5=BA=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../AssemblyCSharpBuilder.Compile.cs | 371 ++----------------
.../CompileUnit/AssemblyCSharpBuilder.Emit.cs | 31 ++
.../AssemblyCSharpBuilder.Event.cs | 36 ++
.../CompileUnit/AssemblyCSharpBuilder.Log.cs | 7 -
.../AssemblyCSharpBuilder.Ouput.cs | 40 +-
.../AssemblyCSharpBuilder.References.cs | 106 +++++
.../SemanticAnalaysis/UsingAnalysistor.cs | 4 +-
.../Compiler/Utils/RuntimeInnerHelper.cs | 2 +-
.../Extension/NatashaDiagnosticsExtension.cs | 2 +-
.../Utils/NatashaFileRepeateHelper.cs | 21 +
10 files changed, 271 insertions(+), 349 deletions(-)
create mode 100644 src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Emit.cs
create mode 100644 src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Event.cs
create mode 100644 src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.References.cs
create mode 100644 src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaFileRepeateHelper.cs
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs
index 84f004a8..ddc6da0d 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs
@@ -1,171 +1,54 @@
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
-using Natasha.CSharp.Compiler.Component;
using Natasha.CSharp.Compiler.Component.Exception;
using Natasha.CSharp.Compiler.Utils;
using Natasha.CSharp.Extension.Inner;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
///
-/// 程序集编译构建器 - 编译选项
+/// 程序集编译构建器 - 编译器
///
public sealed partial class AssemblyCSharpBuilder
{
- private Func, IEnumerable>? _referencesFilter;
- private CombineReferenceBehavior _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
- private readonly ReferenceConfiguration _referenceConfiguration = new();
-
-
- ///
- /// 该方法允许共享域参与编译.
- ///
- /// -
- /// [共享域] 元数据参与编译.
- ///
- /// -
- /// [当前域] 元数据参与编译.
- ///
- ///
- ///
- ///
- /// 注:若两个域不同,且存在相同名称元数据,默认优先使用主域的元数据.
- ///
- /// 配置同名元数据的解决策略
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder WithCombineReferences(Action? action = null)
- {
- action?.Invoke(_referenceConfiguration);
- _combineReferenceBehavior = CombineReferenceBehavior.CombineDefault;
- return this;
- }
-
-
- ///
- /// 配置编译元数据的合并行为.
- ///
- /// -
- /// [共享域] 元数据 [不] 参与编译.
- ///
- /// -
- /// [当前域] 元数据参与编译.
- ///
- ///
- ///
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder WithCurrentReferences()
- {
- _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
- return this;
- }
-
- private readonly List _specifiedReferences;
- ///
- /// 使用外部指定的元数据引用进行编译.
- ///
- /// -
- /// [共享域] 元数据 [不] 参与编译.
- ///
- /// -
- /// [当前域] 元数据 [不] 参与编译.
- ///
- ///
- ///
- ///
- /// 使用 ClearOutsideReferences 可以清除本次传递的元数据引用.
- ///
- ///
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder WithSpecifiedReferences(IEnumerable metadataReferences)
- {
- lock (_specifiedReferences)
- {
- _specifiedReferences.AddRange(metadataReferences);
- }
- _combineReferenceBehavior = CombineReferenceBehavior.UseSpecified;
- return this;
- }
-
- ///
- /// 清除由 WithSpecifiedReferences 方法传入的元数据引用.
- ///
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder ClearOutsideReferences()
- {
- lock (_specifiedReferences)
- {
- _specifiedReferences.Clear();
- }
- return this;
- }
-
-
- ///
- /// 配置元数据引用过滤策略.
- ///
- ///
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder SetReferencesFilter(Func, IEnumerable>? referencesFilter)
- {
- _referencesFilter = referencesFilter;
- return this;
- }
-
- ///
- /// 流编译成功之后触发的事件.
- ///
- ///
- /// 此时已编译结束,程序集已经生成并加载.
- ///
- public event Action? CompileSucceedEvent;
-
-
- ///
- /// 流编译失败之后触发的事件.
- ///
- ///
- /// 此时已经编译结束, 但是编译失败.
- ///
- public event Action>? CompileFailedEvent;
-
-
- private ConcurrentQueue>? _emitOptionHandle;
///
- /// 追加对 emitOption 的处理逻辑.
- ///
- /// - 一次性配置,不可重用.
- /// - 多次调用会进入配置队列.
- /// - 调用 后清空队列.
- /// - 调用 后清空队列.
- /// - 调用 后清空队列.
+ /// 重复编译
+ ///
+ /// -
+ /// 该方法逻辑:
+ ///
+ /// - 用 WithPreCompilationOptions() 方法阻止创建新的 编译选项.
+ /// - 用 WithPreCompilationReferences() 方法阻止覆盖新的引用.
+ ///
+ ///
+ /// -
+ /// 提示:
+ ///
+ /// - 若之前使用了 ConfigEmitOptions. 需要重新再写一遍.
+ /// - 若已存在文件 a.dll,则生成 repeate.guid.a.dll.
+ /// - WithForceCleanFile(); 可强制清除已存在文件.
+ /// - WithoutForceCleanFile(); 则 a.dll 被换成 repeate.guid.a.dll.
+ /// - 指定新的程序集名.
+ /// - 若需要指定新的域.
+ ///
+ ///
///
///
- ///
- /// 注:该配置属于一次性配置,若重复使用该配置逻辑,请在这次编译后重新调用该方法.
- ///
- ///
- /// 链式对象(调用方法的实例本身).
- public AssemblyCSharpBuilder ConfigEmitOptions(Func handleAndReturnNewEmitOption)
+ ///
+ public AssemblyCSharpBuilder Reset()
{
- _emitOptionHandle ??= new ConcurrentQueue>();
- _emitOptionHandle.Enqueue(handleAndReturnNewEmitOption);
+ WithPreCompilationOptions();
+ WithPreCompilationReferences();
return this;
}
///
/// 编译并获取程序集.
- ///
- /// - 编译后的信息获取
///
/// - 用 获取编译配置载体.
/// - 用 获取诊断结果.
- /// - 用 获取运行抛出的异常结果.
+ /// - 用 获取抛出的异常结果.
/// - 用 监听成功编译结果.
/// - 用 监听失败编译结果.
///
@@ -182,15 +65,6 @@ public AssemblyCSharpBuilder ConfigEmitOptions(Func ha
///
///
///
- ///
- /// - 重复编译
- ///
- /// - 查看您所使用过的 Config 开头方法的注释.
- /// - 用 方法使 Builder 可以继续使用.
- /// - 用 方法清空上一次记录的输出路径. 如果第二编译需要输出,请重新指定路径.
- ///
- ///
- ///
///
public void CompileWithoutAssembly()
{
@@ -209,7 +83,8 @@ public void CompileWithoutAssembly()
Stream? xmlStream = null;
if (DllFilePath != string.Empty)
{
- dllStream = File.Create(DllFilePath);
+ dllStream = File.Create(FileHandle(DllFilePath));
+
}
else
{
@@ -218,7 +93,7 @@ public void CompileWithoutAssembly()
if (CommentFilePath != string.Empty)
{
- xmlStream = File.Create(CommentFilePath);
+ xmlStream = File.Create(FileHandle(CommentFilePath));
}
var debugInfoFormat = _debugConfiguration._informationFormat;
@@ -238,16 +113,7 @@ public void CompileWithoutAssembly()
Directory.CreateDirectory(tempPdbOutputFolder);
}
}
- if (File.Exists(PdbFilePath))
- {
- var tempPdbOutputFolder = Path.Combine(GlobalOutputFolder, Domain.Name!);
- PdbFilePath = Path.Combine(tempPdbOutputFolder, $"repeate.{AssemblyName}.{Guid.NewGuid():N}.pdb");
- if (!Directory.Exists(tempPdbOutputFolder))
- {
- Directory.CreateDirectory(tempPdbOutputFolder);
- }
- }
- pdbStream = File.Create(PdbFilePath);
+ pdbStream = File.Create(FileHandle(PdbFilePath));
}
else
{
@@ -306,15 +172,12 @@ public void CompileWithoutAssembly()
#endif
}
-
///
/// 编译并获取程序集.
- ///
- /// - 编译后的信息获取
///
/// - 用 获取编译配置载体.
/// - 用 获取诊断结果.
- /// - 用 获取运行抛出的异常结果.
+ /// - 用 获取抛出的异常结果.
/// - 用 监听成功编译结果.
/// - 用 监听失败编译结果.
///
@@ -331,15 +194,6 @@ public void CompileWithoutAssembly()
///
///
///
- ///
- /// - 重复编译
- ///
- /// - 查看您所使用过的 Config 开头方法的注释.
- /// - 用 方法使 Builder 可以继续使用.
- /// - 用 方法清空上一次记录的输出路径. 如果第二编译需要输出,请重新指定路径.
- ///
- ///
- ///
///
///
/// 注:若不需要加载到域,请使用 CompileWithoutAssembly 方法.
@@ -363,16 +217,15 @@ public Assembly GetAssembly()
Stream? xmlStream = null;
if (DllFilePath != string.Empty)
{
- dllStream = File.Create(DllFilePath);
+ dllStream = File.Create(FileHandle(DllFilePath));
}
else
{
dllStream = new MemoryStream();
}
-
if (CommentFilePath != string.Empty)
{
- xmlStream = File.Create(CommentFilePath);
+ xmlStream = File.Create(FileHandle(CommentFilePath));
}
var debugInfoFormat = _debugConfiguration._informationFormat;
@@ -396,27 +249,8 @@ public Assembly GetAssembly()
Directory.CreateDirectory(tempPdbOutputFolder);
}
}
- if (File.Exists(PdbFilePath))
- {
- var tempPdbOutputFolder = Path.Combine(GlobalOutputFolder, Domain.Name!);
- PdbFilePath = Path.Combine(tempPdbOutputFolder, $"repeate.{AssemblyName}.{Guid.NewGuid():N}.pdb");
- if (!Directory.Exists(tempPdbOutputFolder))
- {
- Directory.CreateDirectory(tempPdbOutputFolder);
- }
- }
- pdbStream = File.Create(PdbFilePath);
+ pdbStream = File.Create(FileHandle(PdbFilePath));
}
- //pdbStream = new MemoryStream();
- /*
- if (debugInfoFormat != DebugInformationFormat.Embedded)
- {
-
- }
- else
- {
- PdbFilePath = null;
- }*/
}
else
{
@@ -459,10 +293,7 @@ public Assembly GetAssembly()
if (compileResult.Success)
{
dllStream.Position = 0;
- if (pdbStream != null)
- {
- pdbStream.Dispose();
- }
+ pdbStream?.Dispose();
assembly = Domain.LoadAssemblyFromStream(dllStream, null);
LoadContext!.LoadMetadataWithAssembly(assembly);
CompileSucceedEvent?.Invoke(_compilation, assembly!);
@@ -482,136 +313,4 @@ public Assembly GetAssembly()
#endif
return assembly;
}
-
- ///
- /// 热重载相关(未完成,无法使用)
- ///
- ///
- ///
- private unsafe Assembly UpdateAssembly(Assembly oldAssembly)
- {
- GetAvailableCompilation();
- if (Domain!.Name != "Default")
- {
- Domain.SetAssemblyLoadBehavior(_domainConfiguration._dependencyLoadBehavior);
- }
-
-#if DEBUG
- Stopwatch stopwatch = new();
- stopwatch.Start();
-#endif
- Stream dllStream = new MemoryStream();
- Stream pdbStream = new MemoryStream();
- Stream metaStream = new MemoryStream();
- Stream? xmlStream = null;
- if (DllFilePath != string.Empty)
- {
- dllStream = File.Create(DllFilePath);
- }
-
- if (CommentFilePath != string.Empty)
- {
- xmlStream = File.Create(CommentFilePath);
- }
-
- var debugInfoFormat = _debugConfiguration._informationFormat;
- debugInfoFormat ??= PdbHelpers.GetPlatformSpecificDebugInformationFormat();
- if (_compilation!.Options.OptimizationLevel == OptimizationLevel.Debug)
- {
-
- if (debugInfoFormat != DebugInformationFormat.Embedded)
- {
- if (string.IsNullOrEmpty(PdbFilePath))
- {
- var tempPdbOutputFolder = Path.Combine(GlobalOutputFolder, Domain.Name!);
- PdbFilePath = Path.Combine(tempPdbOutputFolder, $"{AssemblyName}.pdb");
- if (!Directory.Exists(tempPdbOutputFolder))
- {
- Directory.CreateDirectory(tempPdbOutputFolder);
- }
- }
- if (File.Exists(PdbFilePath))
- {
- var tempPdbOutputFolder = Path.Combine(GlobalOutputFolder, Domain.Name!);
- PdbFilePath = Path.Combine(tempPdbOutputFolder, $"repeate.{AssemblyName}.{Guid.NewGuid():N}.pdb");
- if (!Directory.Exists(tempPdbOutputFolder))
- {
- Directory.CreateDirectory(tempPdbOutputFolder);
- }
- }
- pdbStream = File.Create(PdbFilePath);
- }
- else
- {
- PdbFilePath = null;
- }
- }
-
- var emitOption = new EmitOptions(
- //runtimeMetadataVersion: Assembly.GetExecutingAssembly().ImageRuntimeVersion,
- //instrumentationKinds: [InstrumentationKind.TestCoverage],
- includePrivateMembers: _includePrivateMembers,
- metadataOnly: _isReferenceAssembly,
- pdbFilePath: PdbFilePath,
- debugInformationFormat: debugInfoFormat!.Value,
- pdbChecksumAlgorithm: debugInfoFormat != null ? default(HashAlgorithmName) : null
- );
-
- if (_emitOptionHandle != null)
- {
- while (!_emitOptionHandle.IsEmpty)
- {
- while (_emitOptionHandle.TryDequeue(out var func))
- {
- emitOption = func(emitOption);
- }
- }
- }
-
- var compileResult = _compilation.Emit(
- dllStream,
- pdbStream: pdbStream,
- xmlDocumentationStream: xmlStream,
- //options: emitOption,
- metadataPEStream: metaStream
-
- );
- LogCompilationEvent?.Invoke(_compilation.GetNatashaLog());
-
-
- if (compileResult.Success)
- {
- var ilDelta = AsReadOnlySpan(dllStream);
- var pdbDelta = AsReadOnlySpan(pdbStream);
- var metadataDelta = AsReadOnlySpan(metaStream);
- RuntimeInnerHelper.ApplyUpdate(oldAssembly, metadataDelta, ilDelta, null);
- dllStream.Dispose();
- pdbStream.Dispose();
- metaStream.Dispose();
- xmlStream?.Dispose();
- return oldAssembly!;
-
- }
- else
- {
- dllStream.Dispose();
- pdbStream.Dispose();
- metaStream.Dispose();
- xmlStream?.Dispose();
- CompileFailedEvent?.Invoke(_compilation, compileResult.Diagnostics);
- _exception = NatashaExceptionAnalyzer.GetCompileException(_compilation, compileResult.Diagnostics);
- throw _exception;
- }
-
- static ReadOnlySpan AsReadOnlySpan(Stream input)
- {
- input.Seek(0, SeekOrigin.Begin);
- // 创建一个 MemoryStream 对象来保存 Stream 的数据
- using MemoryStream ms = new();
- input.CopyTo(ms);
-
- // 将 MemoryStream 的数据转换为 Span 对象
- return ms.GetBuffer().AsSpan();
- }
- }
}
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Emit.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Emit.cs
new file mode 100644
index 00000000..9f603d45
--- /dev/null
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Emit.cs
@@ -0,0 +1,31 @@
+using Microsoft.CodeAnalysis.Emit;
+using System;
+using System.Collections.Concurrent;
+///
+/// 程序集编译构建器 - EMIT选项
+///
+public sealed partial class AssemblyCSharpBuilder
+{
+ private ConcurrentQueue>? _emitOptionHandle;
+ ///
+ /// 追加对 emitOption 的处理逻辑.
+ ///
+ /// - 一次性配置,不可重用.
+ /// - 多次调用会进入配置队列.
+ /// - 调用 后清空队列.
+ /// - 调用 后清空队列.
+ /// - 调用 后清空队列.
+ ///
+ ///
+ ///
+ /// 注:该配置属于一次性配置,若重复使用该配置逻辑,请在这次编译后重新调用该方法.
+ ///
+ ///
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder ConfigEmitOptions(Func handleAndReturnNewEmitOption)
+ {
+ _emitOptionHandle ??= new ConcurrentQueue>();
+ _emitOptionHandle.Enqueue(handleAndReturnNewEmitOption);
+ return this;
+ }
+}
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Event.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Event.cs
new file mode 100644
index 00000000..8d0be47c
--- /dev/null
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Event.cs
@@ -0,0 +1,36 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System;
+using System.Collections.Immutable;
+using System.Reflection;
+
+///
+/// 程序集编译构建器 - 事件
+///
+public sealed partial class AssemblyCSharpBuilder
+{
+ ///
+ /// 监听编译日志事件,默认不监听.
+ ///
+ ///
+ /// 注:该事件会被缓存,复用时无需重复添加方法.
+ ///
+ public event Action? LogCompilationEvent;
+ ///
+ /// 流编译成功之后触发的事件.
+ ///
+ ///
+ /// 此时已编译结束,程序集已经生成并加载.
+ ///
+ public event Action? CompileSucceedEvent;
+
+
+ ///
+ /// 流编译失败之后触发的事件.
+ ///
+ ///
+ /// 此时已经编译结束, 但是编译失败.
+ ///
+ public event Action>? CompileFailedEvent;
+}
+
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs
index a3ecdfa5..8149fa54 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs
@@ -2,13 +2,6 @@
public sealed partial class AssemblyCSharpBuilder
{
- ///
- /// 监听编译日志事件,默认不监听.
- ///
- ///
- /// 注:该事件会被缓存,复用时无需重复添加方法.
- ///
- public event Action? LogCompilationEvent;
///
/// 和使用 += log =>{} 一样.
///
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs
index 0803cbc6..94c28639 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs
@@ -1,4 +1,5 @@
-using System;
+using Natasha.CSharp.Compiler.Utils;
+using System;
using System.IO;
///
@@ -27,7 +28,25 @@ static AssemblyCSharpBuilder()
}
}
-
+ private bool _cleanOutput;
+ ///
+ /// 重复编译时,强制清除已存在的文件.
+ ///
+ ///
+ public AssemblyCSharpBuilder WithForceCleanOutput()
+ {
+ _cleanOutput = true;
+ return this;
+ }
+ ///
+ /// 重复编译时,不清除已存在的文件. 使用 old -> repeate.guid.oldname 进行替换.(不指定默认使用该方案)
+ ///
+ ///
+ public AssemblyCSharpBuilder WithoutForceCleanOutput()
+ {
+ _cleanOutput = false;
+ return this;
+ }
///
/// 设置程序集名称.
///
@@ -132,6 +151,23 @@ public AssemblyCSharpBuilder WithFileOutput(string? folder = null)
CommentFilePath = Path.Combine(OutputFolder, $"{AssemblyName}.xml");
return this;
}
+
+
+ private string FileHandle(string file)
+ {
+ if (File.Exists(DllFilePath))
+ {
+ if (_cleanOutput)
+ {
+ File.Delete(DllFilePath);
+ }
+ else
+ {
+ return NatashaFileRepeateHelper.GetAvaliableFilePath(DllFilePath);
+ }
+ }
+ return file;
+ }
#endregion
}
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.References.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.References.cs
new file mode 100644
index 00000000..fac913b1
--- /dev/null
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.References.cs
@@ -0,0 +1,106 @@
+using Microsoft.CodeAnalysis;
+using System;
+using System.Collections.Generic;
+///
+/// 程序集编译构建器 - 引用选项
+///
+public sealed partial class AssemblyCSharpBuilder
+{
+ private Func, IEnumerable>? _referencesFilter;
+ private CombineReferenceBehavior _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
+ private readonly ReferenceConfiguration _referenceConfiguration = new();
+ private readonly List _specifiedReferences;
+
+ ///
+ /// 该方法允许共享域参与编译.
+ ///
+ /// -
+ /// [共享域] 元数据 [参与] 编译.
+ ///
+ /// -
+ /// [当前域] 元数据 [参与] 编译.
+ ///
+ ///
+ ///
+ ///
+ /// 注:若两个域不同,且存在相同名称元数据,默认优先使用主域的元数据.
+ ///
+ /// 配置同名元数据的解决策略
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder WithCombineReferences(Action? action = null)
+ {
+ action?.Invoke(_referenceConfiguration);
+ _combineReferenceBehavior = CombineReferenceBehavior.CombineDefault;
+ return this;
+ }
+
+
+ ///
+ /// 配置编译元数据的合并行为.
+ ///
+ /// -
+ /// [共享域] 元数据 [不参与] 编译.
+ ///
+ /// -
+ /// [当前域] 元数据 [参与] 编译.
+ ///
+ ///
+ ///
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder WithCurrentReferences()
+ {
+ _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
+ return this;
+ }
+
+ ///
+ /// 使用外部指定的元数据引用进行编译.
+ ///
+ /// -
+ /// [共享域] 元数据 [不参与] 编译.
+ ///
+ /// -
+ /// [当前域] 元数据 [不参与] 编译.
+ ///
+ ///
+ ///
+ ///
+ /// 使用 ClearOutsideReferences 可以清除本次传递的元数据引用.
+ ///
+ ///
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder WithSpecifiedReferences(IEnumerable metadataReferences)
+ {
+ lock (_specifiedReferences)
+ {
+ _specifiedReferences.AddRange(metadataReferences);
+ }
+ _combineReferenceBehavior = CombineReferenceBehavior.UseSpecified;
+ return this;
+ }
+
+ ///
+ /// 清除由 WithSpecifiedReferences 方法传入的元数据引用.
+ ///
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder ClearOutsideReferences()
+ {
+ lock (_specifiedReferences)
+ {
+ _specifiedReferences.Clear();
+ }
+ return this;
+ }
+
+
+ ///
+ /// 配置元数据引用过滤策略.
+ ///
+ ///
+ /// 链式对象(调用方法的实例本身).
+ public AssemblyCSharpBuilder SetReferencesFilter(Func, IEnumerable>? referencesFilter)
+ {
+ _referencesFilter = referencesFilter;
+ return this;
+ }
+}
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs
index 5228ba0b..02007a94 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs
@@ -70,13 +70,13 @@ static UsingAnalysistor()
var node = error.GetTypeSyntaxNode(root);
if (node != null)
{
- NatashaDiagnosticsExtension.RemoveUsingAndNode(node, errorNodes);
+ node.RemoveUsingAndNode(errorNodes);
}
}
//命名空间“namespace”中不存在类型或命名空间名“name”(是否缺少程序集引用?)
else if (error.Id == "CS0234")
{
- error.RemoveUsingAndNodesFromStartName(root, errorNodes);
+ error.RemoveDefaultUsingAndNodesByStartName(root, errorNodes);
}
}
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs
index ff27fcdd..5fc6d4b2 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs
@@ -11,7 +11,7 @@ internal unsafe static class RuntimeInnerHelper
internal readonly static ApplyUpdateDelegate ApplyUpdate;
static RuntimeInnerHelper()
{
- AssemblyCSharpBuilder builder = new AssemblyCSharpBuilder();
+ AssemblyCSharpBuilder builder = new();
var assembly = builder
.UseDefaultLoadContext()
.UseSimpleMode()
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaDiagnosticsExtension.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaDiagnosticsExtension.cs
index 3752576b..93ac5297 100644
--- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaDiagnosticsExtension.cs
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaDiagnosticsExtension.cs
@@ -42,7 +42,7 @@ public static void RemoveUsingAndNode(this UsingDirectiveSyntax usingDirectiveSy
}
- public static void RemoveUsingAndNodesFromStartName(this Diagnostic diagnostic, CompilationUnitSyntax root, HashSet removeCollection)
+ public static void RemoveDefaultUsingAndNodesByStartName(this Diagnostic diagnostic, CompilationUnitSyntax root, HashSet removeCollection)
{
var usingNode = GetTypeSyntaxNode(diagnostic, root);
if (usingNode!=null)
diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaFileRepeateHelper.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaFileRepeateHelper.cs
new file mode 100644
index 00000000..6858adaa
--- /dev/null
+++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaFileRepeateHelper.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Natasha.CSharp.Compiler.Utils
+{
+ internal static class NatashaFileRepeateHelper
+ {
+ public static string GetAvaliableFilePath(string file)
+ {
+ var tempOutputFolder = Path.GetDirectoryName(file);
+ if (!Directory.Exists(tempOutputFolder))
+ {
+ Directory.CreateDirectory(tempOutputFolder);
+ }
+ var tempFileName = Path.GetFileName(file);
+ return Path.Combine(tempOutputFolder, $"repeate.{Guid.NewGuid():N}.{tempFileName}");
+ }
+ }
+}