This commit is contained in:
nub31
2025-09-16 18:22:20 +02:00
parent 826f8ffad3
commit 9c1cdf19e6
7 changed files with 349 additions and 422 deletions

View File

@@ -32,7 +32,7 @@ public enum BinaryOperator
public abstract record ExpressionNode(TypeNode Type) : Node;
public abstract record LValueExpressionNode(TypeNode Type) : RValueExpressionNode(Type);
public abstract record LValueExpressionNode(TypeNode Type) : ExpressionNode(Type);
public abstract record RValueExpressionNode(TypeNode Type) : ExpressionNode(Type);

View File

@@ -2,6 +2,4 @@
public abstract record Node;
public record BlockNode(List<StatementNode> Statements) : Node;
public record TypedSyntaxTree(List<DefinitionNode> Definitions);
public record BlockNode(List<StatementNode> Statements) : Node;

View File

@@ -1,6 +1,6 @@
namespace NubLang.TypeChecking.Node;
public record StatementNode : Node;
public abstract record StatementNode : Node;
public record StatementExpressionNode(ExpressionNode Expression) : StatementNode;

View File

@@ -1,31 +1,13 @@
using System.Diagnostics.CodeAnalysis;
namespace NubLang.TypeChecking.Node;
namespace NubLang.TypeChecking.Node;
public abstract class TypeNode : IEquatable<TypeNode>
{
public bool IsSimpleType([NotNullWhen(true)] out SimpleTypeNode? simpleType, [NotNullWhen(false)] out ComplexTypeNode? complexType)
{
if (this is SimpleTypeNode st)
{
complexType = null;
simpleType = st;
return true;
}
if (this is ComplexTypeNode ct)
{
complexType = ct;
simpleType = null;
return false;
}
throw new ArgumentException($"Type {this} is not a simple type nor a complex type");
}
public abstract bool IsValueType { get; }
public abstract bool IsScalar { get; }
public override bool Equals(object? obj) => obj is TypeNode other && Equals(other);
public abstract bool Equals(TypeNode? other);
public abstract override int GetHashCode();
public abstract override string ToString();
@@ -33,90 +15,71 @@ public abstract class TypeNode : IEquatable<TypeNode>
public static bool operator !=(TypeNode? left, TypeNode? right) => !Equals(left, right);
}
public enum StorageSize
public class VoidTypeNode : TypeNode
{
Void,
I8,
I16,
I32,
I64,
U8,
U16,
U32,
U64,
F32,
F64
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => "void";
public override bool Equals(TypeNode? other) => other is VoidTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(VoidTypeNode));
}
public abstract class SimpleTypeNode : TypeNode
public sealed class IntTypeNode(bool signed, int width) : TypeNode
{
public abstract StorageSize StorageSize { get; }
}
public override bool IsValueType => true;
public override bool IsScalar => true;
#region Simple types
public class IntTypeNode(bool signed, int width) : SimpleTypeNode
{
public bool Signed { get; } = signed;
public int Width { get; } = width;
public override StorageSize StorageSize => Signed switch
{
true => Width switch
{
8 => StorageSize.I8,
16 => StorageSize.I16,
32 => StorageSize.I32,
64 => StorageSize.I64,
_ => throw new ArgumentOutOfRangeException(nameof(Width))
},
false => Width switch
{
8 => StorageSize.U8,
16 => StorageSize.U16,
32 => StorageSize.U32,
64 => StorageSize.U64,
_ => throw new ArgumentOutOfRangeException(nameof(Width))
}
};
public override string ToString() => $"{(Signed ? "i" : "u")}{Width}";
public override bool Equals(TypeNode? other) => other is IntTypeNode @int && @int.Width == Width && @int.Signed == Signed;
public override int GetHashCode() => HashCode.Combine(typeof(IntTypeNode), Signed, Width);
}
public class FloatTypeNode(int width) : SimpleTypeNode
public sealed class FloatTypeNode(int width) : TypeNode
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public int Width { get; } = width;
public override StorageSize StorageSize => Width switch
{
32 => StorageSize.F32,
64 => StorageSize.F64,
_ => throw new ArgumentOutOfRangeException(nameof(Width))
};
public override string ToString() => $"f{Width}";
public override bool Equals(TypeNode? other) => other is FloatTypeNode @int && @int.Width == Width;
public override bool Equals(TypeNode? other) => other is FloatTypeNode @float && @float.Width == Width;
public override int GetHashCode() => HashCode.Combine(typeof(FloatTypeNode), Width);
}
public class BoolTypeNode : SimpleTypeNode
public class BoolTypeNode : TypeNode
{
public override StorageSize StorageSize => StorageSize.U8;
public override bool IsValueType => true;
public override bool IsScalar => true;
public override string ToString() => "bool";
public override bool Equals(TypeNode? other) => other is BoolTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(BoolTypeNode));
}
public class FuncTypeNode(List<TypeNode> parameters, TypeNode returnType) : SimpleTypeNode
public sealed class PointerTypeNode(TypeNode baseType) : TypeNode
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public TypeNode BaseType { get; } = baseType;
public override string ToString() => "^" + BaseType;
public override bool Equals(TypeNode? other) => other is PointerTypeNode pointer && BaseType.Equals(pointer.BaseType);
public override int GetHashCode() => HashCode.Combine(typeof(PointerTypeNode), BaseType);
}
public class FuncTypeNode(List<TypeNode> parameters, TypeNode returnType) : TypeNode
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public List<TypeNode> Parameters { get; } = parameters;
public TypeNode ReturnType { get; } = returnType;
public override StorageSize StorageSize => StorageSize.U64;
public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
public override bool Equals(TypeNode? other) => other is FuncTypeNode func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters);
@@ -134,44 +97,19 @@ public class FuncTypeNode(List<TypeNode> parameters, TypeNode returnType) : Simp
}
}
public class PointerTypeNode(TypeNode baseType) : SimpleTypeNode
public class StructTypeNode(string module, string name, List<StructTypeField> fields, List<StructTypeFunc> functions) : TypeNode
{
public TypeNode BaseType { get; } = baseType;
public override bool IsValueType => true;
public override bool IsScalar => false;
public override StorageSize StorageSize => StorageSize.U64;
public string Module { get; } = module;
public string Name { get; } = name;
public List<StructTypeField> Fields { get; set; } = fields;
public List<StructTypeFunc> Functions { get; set; } = functions;
public override string ToString() => "^" + BaseType;
public override bool Equals(TypeNode? other) => other is PointerTypeNode pointer && BaseType.Equals(pointer.BaseType);
public override int GetHashCode() => HashCode.Combine(typeof(PointerTypeNode), BaseType);
}
public class VoidTypeNode : SimpleTypeNode
{
public override StorageSize StorageSize => StorageSize.Void;
public override string ToString() => "void";
public override bool Equals(TypeNode? other) => other is VoidTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(VoidTypeNode));
}
#endregion
public abstract class ComplexTypeNode : TypeNode;
#region Complex types
public class CStringTypeNode : ComplexTypeNode
{
public override string ToString() => "cstring";
public override bool Equals(TypeNode? other) => other is CStringTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(CStringTypeNode));
}
public class StringTypeNode : ComplexTypeNode
{
public override string ToString() => "string";
public override bool Equals(TypeNode? other) => other is StringTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(StringTypeNode));
public override string ToString() => Name;
public override bool Equals(TypeNode? other) => other is StructTypeNode structType && Name == structType.Name && Module == structType.Module;
public override int GetHashCode() => HashCode.Combine(typeof(StructTypeNode), Name);
}
public class StructTypeField(string name, TypeNode type, bool hasDefaultValue)
@@ -187,26 +125,34 @@ public class StructTypeFunc(string name, FuncTypeNode type)
public FuncTypeNode Type { get; } = type;
}
public class StructTypeNode(string module, string name, List<StructTypeField> fields, List<StructTypeFunc> functions) : ComplexTypeNode
public class CStringTypeNode : TypeNode
{
public string Module { get; } = module;
public string Name { get; } = name;
public List<StructTypeField> Fields { get; set; } = fields;
public List<StructTypeFunc> Functions { get; set; } = functions;
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => Name;
public override bool Equals(TypeNode? other) => other is StructTypeNode structType && Name == structType.Name && Module == structType.Module;
public override int GetHashCode() => HashCode.Combine(typeof(StructTypeNode), Name);
public override string ToString() => "cstring";
public override bool Equals(TypeNode? other) => other is CStringTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(CStringTypeNode));
}
public class ArrayTypeNode(TypeNode elementType) : ComplexTypeNode
public class StringTypeNode : TypeNode
{
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => "string";
public override bool Equals(TypeNode? other) => other is StringTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(StringTypeNode));
}
public class ArrayTypeNode(TypeNode elementType) : TypeNode
{
public override bool IsValueType => false;
public override bool IsScalar => false;
public TypeNode ElementType { get; } = elementType;
public override string ToString() => "[]" + ElementType;
public override bool Equals(TypeNode? other) => other is ArrayTypeNode array && ElementType.Equals(array.ElementType);
public override int GetHashCode() => HashCode.Combine(typeof(ArrayTypeNode), ElementType);
}
#endregion
}

View File

@@ -117,15 +117,25 @@ public sealed class TypeChecker
scope.Declare(new Identifier(parameter.Name, ResolveType(parameter.Type), IdentifierKind.FunctionParameter));
}
var signature = CheckFuncSignature(node.Signature);
BlockNode? body = null;
if (node.Body != null)
{
_funcReturnTypes.Push(ResolveType(node.Signature.ReturnType));
_funcReturnTypes.Push(signature.ReturnType);
body = CheckBlock(node.Body, scope);
// Insert implicit return for void functions
if (signature.ReturnType is VoidTypeNode && body.Statements.LastOrDefault() is not ReturnNode)
{
body.Statements.Add(new ReturnNode(Optional<ExpressionNode>.Empty()));
}
_funcReturnTypes.Pop();
}
return new FuncNode(_syntaxTree.Metadata.ModuleName, node.Name, node.ExternSymbol, CheckFuncSignature(node.Signature), body);
return new FuncNode(_syntaxTree.Metadata.ModuleName, node.Name, node.ExternSymbol, signature, body);
}
private StatementNode CheckStatement(StatementSyntax node)
@@ -715,9 +725,29 @@ public sealed class TypeChecker
_scopes.Push(scope ?? Scope.SubScope());
var reachable = true;
var warnedUnreachable = false;
foreach (var statement in node.Statements)
{
statements.Add(CheckStatement(statement));
var checkedStatement = CheckStatement(statement);
if (reachable)
{
statements.Add(checkedStatement);
if (checkedStatement is ReturnNode or BreakNode or ContinueNode)
{
reachable = false;
}
}
else
{
if (!warnedUnreachable)
{
Diagnostics.Add(Diagnostic.Warning("Statement is unreachable").At(statement).Build());
warnedUnreachable = true;
}
}
}
_scopes.Pop();