...
This commit is contained in:
267
compiler/NubLang/Types/NubType.cs
Normal file
267
compiler/NubLang/Types/NubType.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace NubLang.Types;
|
||||
|
||||
public abstract class NubType : IEquatable<NubType>
|
||||
{
|
||||
public abstract ulong GetSize();
|
||||
public abstract ulong GetAlignment();
|
||||
public abstract bool IsAggregate();
|
||||
|
||||
public override bool Equals(object? obj) => obj is NubType other && Equals(other);
|
||||
public abstract bool Equals(NubType? other);
|
||||
|
||||
public abstract override int GetHashCode();
|
||||
public abstract override string ToString();
|
||||
|
||||
public static bool operator ==(NubType? left, NubType? right) => Equals(left, right);
|
||||
public static bool operator !=(NubType? left, NubType? right) => !Equals(left, right);
|
||||
}
|
||||
|
||||
public class NubVoidType : NubType
|
||||
{
|
||||
public override ulong GetSize() => 8;
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => "void";
|
||||
public override bool Equals(NubType? other) => other is NubVoidType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubVoidType));
|
||||
}
|
||||
|
||||
public sealed class NubIntType(bool signed, ulong width) : NubType
|
||||
{
|
||||
public bool Signed { get; } = signed;
|
||||
public ulong Width { get; } = width;
|
||||
|
||||
public override ulong GetSize() => Width / 8;
|
||||
public override ulong GetAlignment() => Width / 8;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => $"{(Signed ? "i" : "u")}{Width}";
|
||||
public override bool Equals(NubType? other) => other is NubIntType @int && @int.Width == Width && @int.Signed == Signed;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubIntType), Signed, Width);
|
||||
}
|
||||
|
||||
public sealed class NubFloatType(ulong width) : NubType
|
||||
{
|
||||
public ulong Width { get; } = width;
|
||||
|
||||
public override ulong GetSize() => Width / 8;
|
||||
public override ulong GetAlignment() => Width / 8;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => $"f{Width}";
|
||||
public override bool Equals(NubType? other) => other is NubFloatType @float && @float.Width == Width;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubFloatType), Width);
|
||||
}
|
||||
|
||||
public class NubBoolType : NubType
|
||||
{
|
||||
public override ulong GetSize() => 1;
|
||||
public override ulong GetAlignment() => 1;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => "bool";
|
||||
public override bool Equals(NubType? other) => other is NubBoolType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubBoolType));
|
||||
}
|
||||
|
||||
public sealed class NubPointerType(NubType baseType) : NubType
|
||||
{
|
||||
public NubType BaseType { get; } = baseType;
|
||||
|
||||
public override ulong GetSize() => 8;
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => "^" + BaseType;
|
||||
public override bool Equals(NubType? other) => other is NubPointerType pointer && BaseType.Equals(pointer.BaseType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubPointerType), BaseType);
|
||||
}
|
||||
|
||||
public class NubFuncType(List<NubType> parameters, NubType returnType) : NubType
|
||||
{
|
||||
public List<NubType> Parameters { get; } = parameters;
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
|
||||
public override ulong GetSize() => 8;
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => false;
|
||||
|
||||
public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
|
||||
public override bool Equals(NubType? other) => other is NubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = new HashCode();
|
||||
hash.Add(typeof(NubFuncType));
|
||||
hash.Add(ReturnType);
|
||||
foreach (var param in Parameters)
|
||||
{
|
||||
hash.Add(param);
|
||||
}
|
||||
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class NubStructType(string module, string name, bool packed, List<NubStructFieldType> fields) : NubType
|
||||
{
|
||||
public string Module { get; } = module;
|
||||
public string Name { get; } = name;
|
||||
public bool Packed { get; } = packed;
|
||||
public List<NubStructFieldType> Fields { get; set; } = fields;
|
||||
|
||||
public int GetFieldIndex(string name)
|
||||
{
|
||||
return Fields.FindIndex(x => x.Name == name);
|
||||
}
|
||||
|
||||
public Dictionary<string, ulong> GetFieldOffsets()
|
||||
{
|
||||
var offsets = new Dictionary<string, ulong>();
|
||||
ulong offset = 0;
|
||||
|
||||
foreach (var field in Fields)
|
||||
{
|
||||
var alignment = Packed ? 1 : field.Type.GetAlignment();
|
||||
if (!Packed)
|
||||
{
|
||||
var padding = (alignment - offset % alignment) % alignment;
|
||||
offset += padding;
|
||||
}
|
||||
|
||||
offsets[field.Name] = offset;
|
||||
offset += field.Type.GetSize();
|
||||
}
|
||||
|
||||
return offsets;
|
||||
}
|
||||
|
||||
public override ulong GetSize()
|
||||
{
|
||||
var offsets = GetFieldOffsets();
|
||||
if (Fields.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var lastField = Fields.Last();
|
||||
var size = offsets[lastField.Name] + lastField.Type.GetSize();
|
||||
|
||||
if (!Packed)
|
||||
{
|
||||
var structAlignment = GetAlignment();
|
||||
var padding = (structAlignment - size % structAlignment) % structAlignment;
|
||||
size += padding;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public override ulong GetAlignment()
|
||||
{
|
||||
if (Fields.Count == 0)
|
||||
return 1;
|
||||
|
||||
return Packed ? 1 : Fields.Max(f => f.Type.GetAlignment());
|
||||
}
|
||||
|
||||
public override bool IsAggregate() => true;
|
||||
|
||||
public override string ToString() => $"{Module}::{Name}";
|
||||
public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name);
|
||||
}
|
||||
|
||||
public class NubStructFieldType(string name, NubType type, bool hasDefaultValue)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public NubType Type { get; } = type;
|
||||
public bool HasDefaultValue { get; } = hasDefaultValue;
|
||||
}
|
||||
|
||||
public class NubSliceType(NubType elementType) : NubType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
|
||||
public override ulong GetSize() => 16; // note(nub31): Fat pointer
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => true;
|
||||
|
||||
public override string ToString() => "[]" + ElementType;
|
||||
public override bool Equals(NubType? other) => other is NubSliceType slice && ElementType.Equals(slice.ElementType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubSliceType), ElementType);
|
||||
}
|
||||
|
||||
public class NubConstArrayType(NubType elementType, ulong size) : NubType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
public ulong Size { get; } = size;
|
||||
|
||||
public override ulong GetSize() => ElementType.GetSize() * Size;
|
||||
public override ulong GetAlignment() => ElementType.GetAlignment();
|
||||
public override bool IsAggregate() => true;
|
||||
|
||||
public override string ToString() => $"[{Size}]{ElementType}";
|
||||
public override bool Equals(NubType? other) => other is NubConstArrayType array && ElementType.Equals(array.ElementType) && Size == array.Size;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubConstArrayType), ElementType, Size);
|
||||
}
|
||||
|
||||
public class NubArrayType(NubType elementType) : NubType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
|
||||
public override ulong GetSize() => 8;
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => false; // note(nub31): Just a pointer
|
||||
|
||||
public override string ToString() => $"[?]{ElementType}";
|
||||
public override bool Equals(NubType? other) => other is NubArrayType array && ElementType.Equals(array.ElementType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType);
|
||||
}
|
||||
|
||||
public class NubStringType : NubType
|
||||
{
|
||||
public override ulong GetSize() => 16; // note(nub31): Fat pointer
|
||||
public override ulong GetAlignment() => 8;
|
||||
public override bool IsAggregate() => true;
|
||||
|
||||
public override string ToString() => "string";
|
||||
public override bool Equals(NubType? other) => other is NubStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
|
||||
}
|
||||
|
||||
public static class NameMangler
|
||||
{
|
||||
public static string Mangle(params IEnumerable<NubType> types)
|
||||
{
|
||||
var readable = string.Join(":", types.Select(EncodeType));
|
||||
return ComputeShortHash(readable);
|
||||
}
|
||||
|
||||
private static string EncodeType(NubType node) => node switch
|
||||
{
|
||||
NubVoidType => "V",
|
||||
NubBoolType => "B",
|
||||
NubIntType i => (i.Signed ? "I" : "U") + i.Width,
|
||||
NubFloatType f => "F" + f.Width,
|
||||
NubStringType => "S",
|
||||
NubArrayType a => $"A({EncodeType(a.ElementType)})",
|
||||
NubConstArrayType ca => $"CA({EncodeType(ca.ElementType)})",
|
||||
NubSliceType a => $"SL{EncodeType(a.ElementType)}()",
|
||||
NubPointerType p => $"P({EncodeType(p.BaseType)})",
|
||||
NubFuncType fn => $"FN({string.Join(":", fn.Parameters.Select(EncodeType))}:{EncodeType(fn.ReturnType)})",
|
||||
NubStructType st => $"ST({st.Module}:{st.Name})",
|
||||
_ => throw new NotSupportedException($"Cannot encode type: {node}")
|
||||
};
|
||||
|
||||
private static string ComputeShortHash(string input)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(input);
|
||||
var hash = SHA256.HashData(bytes);
|
||||
return Convert.ToHexString(hash[..8]).ToLower();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user