110 lines
4.2 KiB
C#
110 lines
4.2 KiB
C#
using System.IO.Compression;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Compiler;
|
|
|
|
public class NubLib
|
|
{
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = true,
|
|
};
|
|
|
|
public static void Pack(string outputPath, string archivePath, Manifest manifest)
|
|
{
|
|
using var fs = new FileStream(outputPath, FileMode.Create);
|
|
using var zip = new ZipArchive(fs, ZipArchiveMode.Create);
|
|
|
|
var manifestEntry = zip.CreateEntry("manifest.json");
|
|
using (var writer = new StreamWriter(manifestEntry.Open()))
|
|
{
|
|
var serialized = JsonSerializer.Serialize(manifest, JsonOptions);
|
|
|
|
writer.Write(serialized);
|
|
}
|
|
|
|
var archiveEntry = zip.CreateEntry("lib.a");
|
|
|
|
using var entryStream = archiveEntry.Open();
|
|
using var fileStream = File.OpenRead(archivePath);
|
|
|
|
fileStream.CopyTo(entryStream);
|
|
}
|
|
|
|
public static NubLibLoadResult Unpack(string nublibPath)
|
|
{
|
|
using var fs = new FileStream(nublibPath, FileMode.Open, FileAccess.Read);
|
|
using var zip = new ZipArchive(fs, ZipArchiveMode.Read);
|
|
|
|
var manifestEntry = zip.GetEntry("manifest.json") ?? throw new FileNotFoundException("Manifest not found in nublib", "manifest.json");
|
|
|
|
Manifest manifest;
|
|
using (var reader = new StreamReader(manifestEntry.Open()))
|
|
{
|
|
var json = reader.ReadToEnd();
|
|
manifest = JsonSerializer.Deserialize<Manifest>(json, JsonOptions) ?? throw new InvalidDataException("Failed to deserialize manifest.json");
|
|
}
|
|
|
|
var archiveEntry = zip.Entries.FirstOrDefault(e => e.Name.EndsWith(".a")) ?? throw new FileNotFoundException("Archive not found in nublib", "*.a");
|
|
|
|
string tempArchivePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".a");
|
|
using (var entryStream = archiveEntry.Open())
|
|
using (var tempFile = File.Create(tempArchivePath))
|
|
{
|
|
entryStream.CopyTo(tempFile);
|
|
}
|
|
|
|
return new NubLibLoadResult(manifest, tempArchivePath);
|
|
}
|
|
|
|
public record NubLibLoadResult(Manifest Manifest, string ArchivePath);
|
|
}
|
|
|
|
public record Manifest(Dictionary<string, Manifest.Module> Modules)
|
|
{
|
|
public static Manifest Create(ModuleGraph moduleGraph)
|
|
{
|
|
var modules = new Dictionary<string, Module>();
|
|
|
|
foreach (var module in moduleGraph.GetModules())
|
|
{
|
|
var types = module.GetTypes().ToDictionary(x => x.Key, x => ConvertType(x.Value));
|
|
var identifiers = module.GetIdentifiers().ToDictionary(x => x.Key, x => new Module.IdentifierInfo(x.Value.Type, x.Value.Exported, x.Value.Extern, x.Value.MangledName));
|
|
modules[module.Name] = new Module(types, identifiers);
|
|
}
|
|
|
|
return new Manifest(modules);
|
|
|
|
static Module.TypeInfo ConvertType(Compiler.Module.TypeInfo typeInfo)
|
|
{
|
|
return typeInfo switch
|
|
{
|
|
Compiler.Module.TypeInfoStruct s => new Module.TypeInfoStruct(s.Exported, s.Packed, s.Fields.Select(x => new Module.TypeInfoStruct.Field(x.Name, x.Type)).ToList()),
|
|
Compiler.Module.TypeInfoEnum e => new Module.TypeInfoEnum(e.Exported, e.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name, v.Type)).ToList()),
|
|
_ => throw new ArgumentOutOfRangeException(nameof(typeInfo))
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
public record Module(Dictionary<string, Module.TypeInfo> Types, Dictionary<string, Module.IdentifierInfo> Identifiers)
|
|
{
|
|
public record IdentifierInfo(NubType Type, bool Exported, bool Extern, string MangledName);
|
|
|
|
[JsonDerivedType(typeof(TypeInfoStruct), "struct")]
|
|
[JsonDerivedType(typeof(TypeInfoEnum), "enum")]
|
|
public abstract record TypeInfo(bool Exported);
|
|
|
|
public record TypeInfoStruct(bool Exported, bool Packed, IReadOnlyList<TypeInfoStruct.Field> Fields) : TypeInfo(Exported)
|
|
{
|
|
public record Field(string Name, NubType Type);
|
|
}
|
|
|
|
public record TypeInfoEnum(bool Exported, IReadOnlyList<TypeInfoEnum.Variant> Variants) : TypeInfo(Exported)
|
|
{
|
|
public record Variant(string Name, NubType Type);
|
|
}
|
|
}
|
|
} |