Skip to content

Commit

Permalink
Add Visual Basic compilation support
Browse files Browse the repository at this point in the history
  • Loading branch information
KubaZ2 committed Aug 12, 2024
1 parent 208fef3 commit ba17b59
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 18 deletions.
22 changes: 4 additions & 18 deletions Bot/Sharp/Compilation/CSharpCompiler.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using System.Text;

using Basic.Reference.Assemblies;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Sharp.Compilation;

public class CSharpCompiler : ICompiler
public class CSharpCompiler : RoslynCompiler
{
private static readonly CSharpCompilationOptions _executableOptions = new(
outputKind: OutputKind.ConsoleApplication,
Expand All @@ -32,8 +30,6 @@ private static CSharpCompilationOptions GetOptions(SyntaxTree syntaxTree, Compil
return syntaxTree.GetRoot().ChildNodes().Any(node => node.IsKind(SyntaxKind.GlobalStatement)) ? _executableOptions : _libraryOptions;
}

private static readonly MetadataReference[] _references = [.. Net80.References.All, MetadataReference.CreateFromFile(typeof(JitGenericAttribute).Assembly.Location)];

private static readonly SyntaxTree _globalUsingsSyntaxTree = CreateGlobalUsingsSyntaxTree("System",
"System.Collections.Generic",
"System.IO",
Expand All @@ -58,22 +54,12 @@ private static SyntaxTree CreateGlobalUsingsSyntaxTree(params string[] namespace
return CSharpSyntaxTree.ParseText(stringBuilder.ToString());
}

public Language Language => Language.CSharp;
public override Language Language => Language.CSharp;

public ValueTask<bool> CompileAsync(string code, ICollection<Diagnostic> diagnostics, Stream assembly, CompilationOutput? output)
protected override Microsoft.CodeAnalysis.Compilation CreateCompilation(string code, CompilationOutput? output)
{
var syntaxTree = CSharpSyntaxTree.ParseText(code);

var compilation = CSharpCompilation.Create("_", [_globalUsingsSyntaxTree, syntaxTree], _references, GetOptions(syntaxTree, output));

var result = compilation.Emit(assembly);

var resultDiagnostic = result.Diagnostics;
int length = resultDiagnostic.Length;

for (int i = 0; i < length; i++)
diagnostics.Add(resultDiagnostic[i]);

return new(result.Success);
return CSharpCompilation.Create("_", [_globalUsingsSyntaxTree, syntaxTree], _references, GetOptions(syntaxTree, output));
}
}
29 changes: 29 additions & 0 deletions Bot/Sharp/Compilation/RoslynCompiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Basic.Reference.Assemblies;

using Microsoft.CodeAnalysis;

namespace Sharp.Compilation;

public abstract class RoslynCompiler : ICompiler
{
protected static readonly MetadataReference[] _references = [.. Net80.References.All, MetadataReference.CreateFromFile(typeof(JitGenericAttribute).Assembly.Location)];

public abstract Language Language { get; }

protected abstract Microsoft.CodeAnalysis.Compilation CreateCompilation(string code, CompilationOutput? output);

public ValueTask<bool> CompileAsync(string code, ICollection<Diagnostic> diagnostics, Stream assembly, CompilationOutput? output)
{
var compilation = CreateCompilation(code, output);

var result = compilation.Emit(assembly);

var resultDiagnostics = result.Diagnostics;
int length = resultDiagnostics.Length;

for (int i = 0; i < length; i++)
diagnostics.Add(resultDiagnostics[i]);

return new(result.Success);
}
}
64 changes: 64 additions & 0 deletions Bot/Sharp/Compilation/VisualBasicCompiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic;

namespace Sharp.Compilation;

public class VisualBasicCompiler : RoslynCompiler
{
static VisualBasicCompiler()
{
var globalImports = CreateGlobalImports("System",
"Microsoft.VisualBasic",
"System.Collections.Generic",
"System.Linq",
"System.Collections",
"System.Diagnostics",
"System.Threading.Tasks",
"Sharp");

_executableOptions = new(
outputKind: OutputKind.ConsoleApplication,
optimizationLevel: OptimizationLevel.Release,
globalImports: globalImports);

_libraryOptions = new(
outputKind: OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release,
globalImports: globalImports);
}

private static GlobalImport[] CreateGlobalImports(params string[] namespaces)
{
int length = namespaces.Length;
var result = new GlobalImport[length];

for (int i = 0; i < length; i++)
result[i] = GlobalImport.Parse(namespaces[i]);

return result;
}

private static readonly VisualBasicCompilationOptions _executableOptions;

private static readonly VisualBasicCompilationOptions _libraryOptions;

private static VisualBasicCompilationOptions GetOptions(CompilationOutput? output)
{
if (output.HasValue)
return output.GetValueOrDefault() switch
{
CompilationOutput.Executable => _executableOptions,
CompilationOutput.Library => _libraryOptions,
_ => throw new ArgumentOutOfRangeException(nameof(output))
};

return _libraryOptions;
}

public override Language Language => Language.VisualBasic;

protected override Microsoft.CodeAnalysis.Compilation CreateCompilation(string code, CompilationOutput? output)
{
return VisualBasicCompilation.Create("_", [VisualBasicSyntaxTree.ParseText(code)], _references, GetOptions(output));
}
}
3 changes: 3 additions & 0 deletions Bot/Sharp/Language.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ public enum Language : byte
[LanguageAliases("c#", "cs", "csharp")]
CSharp,

[LanguageAliases("vb", "vb.net", "vbnet", "visualbasic", "visualbasic.net", "visualbasicnet")]
VisualBasic,

[LanguageAliases("il", "cil", "msil")]
IL,

Expand Down
1 change: 1 addition & 0 deletions Bot/Sharp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
.AddSingleton<IBackendUriProvider, BackendUriProvider>()
.AddSingleton<IBackendProvider, BackendProvider>()
.AddSingleton<ICompiler, CSharpCompiler>()
.AddSingleton<ICompiler, VisualBasicCompiler>()
.AddSingleton<ICompiler, ILCompiler>()
.AddSingleton<ICompilerProvider, CompilerProvider>()
.AddSingleton<IDecompiler, CSharpDecompiler>()
Expand Down
1 change: 1 addition & 0 deletions Bot/Sharp/Responding/ResponseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public class ResponseProvider(IOptions<Options> options, ICompilationFormatter c
## Support
### Compilation
- C#
- Visual Basic
- IL
### Decompilation
- C#
Expand Down
1 change: 1 addition & 0 deletions Bot/Sharp/Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.7.2" />
<PackageReference Include="ICSharpCode.Decompiler" Version="8.2.0.7535" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
Expand Down

0 comments on commit ba17b59

Please sign in to comment.