...
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Compiler;
|
||||
|
||||
[JsonConverter(typeof(NubTypeJsonConverter))]
|
||||
public abstract class NubType
|
||||
{
|
||||
public abstract override string ToString();
|
||||
@@ -87,61 +89,26 @@ public class NubTypeString : NubType
|
||||
|
||||
public class NubTypeStruct : NubType
|
||||
{
|
||||
private static readonly Dictionary<Signature, NubTypeStruct> Cache = new();
|
||||
private static readonly Dictionary<(string Module, string Name), NubTypeStruct> Cache = new();
|
||||
|
||||
public static NubTypeStruct Get(bool packed, List<Field> fields)
|
||||
public static NubTypeStruct Get(string module, string name)
|
||||
{
|
||||
var sig = new Signature(packed, fields);
|
||||
if (!Cache.TryGetValue((module, name), out var structType))
|
||||
Cache[(module, name)] = structType = new NubTypeStruct(module, name);
|
||||
|
||||
if (!Cache.TryGetValue(sig, out var sturctType))
|
||||
Cache[sig] = sturctType = new NubTypeStruct(packed, fields);
|
||||
|
||||
return sturctType;
|
||||
return structType;
|
||||
}
|
||||
|
||||
private NubTypeStruct(bool packed, List<Field> fields)
|
||||
private NubTypeStruct(string module, string name)
|
||||
{
|
||||
Packed = packed;
|
||||
this.fields = fields;
|
||||
Module = module;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
private NubTypeStruct(bool packed)
|
||||
{
|
||||
Packed = packed;
|
||||
}
|
||||
public string Module { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool Packed { get; }
|
||||
|
||||
private IReadOnlyList<Field>? fields;
|
||||
public IReadOnlyList<Field> Fields
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fields == null)
|
||||
throw new InvalidOperationException("Fields has not been set");
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
public static NubTypeStruct CreateWithoutFields(bool packed)
|
||||
{
|
||||
return new NubTypeStruct(packed);
|
||||
}
|
||||
|
||||
public void SetFields(List<Field> fields)
|
||||
{
|
||||
if (this.fields != null)
|
||||
throw new InvalidOperationException("Fields can only be set once");
|
||||
|
||||
this.fields = fields;
|
||||
Cache[new Signature(Packed, this.fields)] = this;
|
||||
}
|
||||
|
||||
public override string ToString() => $"struct {{ {string.Join(' ', Fields.Select(f => $"{f.Name}: {f.Type}"))} }}";
|
||||
|
||||
public record Field(string Name, NubType Type);
|
||||
private record Signature(bool Packed, IReadOnlyList<Field> Fields);
|
||||
public override string ToString() => $"struct {Module}::{Name}";
|
||||
}
|
||||
|
||||
public class NubTypePointer : NubType
|
||||
@@ -183,7 +150,7 @@ public class NubTypeFunc : NubType
|
||||
public IReadOnlyList<NubType> Parameters { get; }
|
||||
public NubType ReturnType { get; }
|
||||
|
||||
public string MangledName(string name, string module) => SymbolNameGen.Exported(name, module, this);
|
||||
public string MangledName(string name, string module) => Name.Create(name, module, this);
|
||||
|
||||
private NubTypeFunc(List<NubType> parameters, NubType returnType)
|
||||
{
|
||||
@@ -212,15 +179,7 @@ public class TypeEncoder
|
||||
private string EncodeRoot(NubType type)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
EncodeType(sb, type);
|
||||
|
||||
foreach (var definition in structDefinitions.Values.OrderBy(x => x.Index))
|
||||
{
|
||||
Debug.Assert(definition.Encoded != null);
|
||||
sb.Insert(0, definition.Encoded);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
@@ -259,7 +218,11 @@ public class TypeEncoder
|
||||
break;
|
||||
|
||||
case NubTypeStruct st:
|
||||
sb.Append(GetOrCreateStructDefinition(st));
|
||||
sb.Append("T(");
|
||||
sb.Append(st.Module);
|
||||
sb.Append(':');
|
||||
sb.Append(st.Name);
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeFunc fn:
|
||||
@@ -277,35 +240,6 @@ public class TypeEncoder
|
||||
}
|
||||
}
|
||||
|
||||
private string GetOrCreateStructDefinition(NubTypeStruct st)
|
||||
{
|
||||
if (!structDefinitions.TryGetValue(st, out var definition))
|
||||
{
|
||||
definition = new Definition(structDefinitions.Count);
|
||||
structDefinitions[st] = definition;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("D(");
|
||||
sb.Append(st.Packed ? '1' : '0');
|
||||
sb.Append('{');
|
||||
for (var i = 0; i < st.Fields.Count; i++)
|
||||
{
|
||||
var field = st.Fields[i];
|
||||
sb.Append(field.Name);
|
||||
sb.Append(':');
|
||||
EncodeType(sb, field.Type);
|
||||
}
|
||||
sb.Append('}');
|
||||
sb.Append(')');
|
||||
|
||||
var encoded = sb.ToString();
|
||||
definition.Encoded = encoded;
|
||||
}
|
||||
|
||||
return $"T({definition.Index})";
|
||||
}
|
||||
|
||||
private class Definition(int index)
|
||||
{
|
||||
public int Index { get; } = index;
|
||||
@@ -317,7 +251,7 @@ public class TypeDecoder
|
||||
{
|
||||
public static NubType Decode(string encoded)
|
||||
{
|
||||
return new TypeDecoder(encoded).DecodeRoot();
|
||||
return new TypeDecoder(encoded).DecodeType();
|
||||
}
|
||||
|
||||
private TypeDecoder(string encoded)
|
||||
@@ -326,66 +260,7 @@ public class TypeDecoder
|
||||
}
|
||||
|
||||
private readonly string encoded;
|
||||
private int index;
|
||||
private readonly List<NubTypeStruct> structDefinitions = new();
|
||||
|
||||
private NubType DecodeRoot()
|
||||
{
|
||||
// First pass: Collect all declarations
|
||||
while (TryExpect('D'))
|
||||
{
|
||||
Expect('(');
|
||||
var packedChar = Consume();
|
||||
if (packedChar is not '1' and not '0')
|
||||
throw new Exception("Expected '0' or '1' for struct packing");
|
||||
|
||||
Expect('{');
|
||||
while (TryPeek(out var c))
|
||||
{
|
||||
Consume();
|
||||
if (c == '}')
|
||||
break;
|
||||
}
|
||||
|
||||
Expect(')');
|
||||
|
||||
structDefinitions.Add(NubTypeStruct.CreateWithoutFields(packedChar == '1'));
|
||||
}
|
||||
|
||||
index = 0;
|
||||
var defIndex = 0;
|
||||
|
||||
// Second pass: Set field types
|
||||
while (TryExpect('D'))
|
||||
{
|
||||
var fields = new List<NubTypeStruct.Field>();
|
||||
|
||||
Consume();
|
||||
Consume();
|
||||
Consume();
|
||||
|
||||
while (!TryExpect('}'))
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
while (!TryExpect(':'))
|
||||
{
|
||||
sb.Append(Consume());
|
||||
}
|
||||
|
||||
var type = DecodeType();
|
||||
|
||||
fields.Add(new NubTypeStruct.Field(sb.ToString(), type));
|
||||
}
|
||||
Expect(')');
|
||||
|
||||
structDefinitions[defIndex].SetFields(fields);
|
||||
|
||||
defIndex += 1;
|
||||
}
|
||||
|
||||
return DecodeType();
|
||||
}
|
||||
private int index = 0;
|
||||
|
||||
private NubType DecodeType()
|
||||
{
|
||||
@@ -443,10 +318,21 @@ public class TypeDecoder
|
||||
|
||||
private NubTypeStruct DecodeStruct()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
Expect('(');
|
||||
var index = ExpectInt();
|
||||
Expect(')');
|
||||
return structDefinitions[index];
|
||||
while (!TryExpect(':'))
|
||||
sb.Append(Consume());
|
||||
|
||||
var module = sb.ToString();
|
||||
sb.Clear();
|
||||
|
||||
while (!TryExpect(')'))
|
||||
sb.Append(Consume());
|
||||
|
||||
var name = sb.ToString();
|
||||
|
||||
return NubTypeStruct.Get(module, name);
|
||||
}
|
||||
|
||||
private bool TryPeek(out char c)
|
||||
@@ -517,6 +403,19 @@ public class TypeDecoder
|
||||
}
|
||||
}
|
||||
|
||||
public class NubTypeJsonConverter : JsonConverter<NubType>
|
||||
{
|
||||
public override NubType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return TypeDecoder.Decode(reader.GetString()!);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, NubType value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(TypeEncoder.Encode(value));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Hashing
|
||||
{
|
||||
public static ulong Fnv1a64(string text)
|
||||
@@ -535,14 +434,14 @@ public static class Hashing
|
||||
}
|
||||
}
|
||||
|
||||
public static class SymbolNameGen
|
||||
public static class Name
|
||||
{
|
||||
public static string Exported(string module, string function, NubType type)
|
||||
public static string Create(string module, string name, NubType type)
|
||||
{
|
||||
var canonical = TypeEncoder.Encode(type);
|
||||
var hash = Hashing.Fnv1a64(canonical);
|
||||
|
||||
return $"nub_{Sanitize(module)}_{Sanitize(function)}_{hash:x16}";
|
||||
return $"nub_{Sanitize(module)}_{Sanitize(name)}_{hash:x16}";
|
||||
}
|
||||
|
||||
private static string Sanitize(string s)
|
||||
|
||||
Reference in New Issue
Block a user