defer and struct hooks

This commit is contained in:
nub31
2025-09-19 23:08:12 +02:00
parent 609e1b5d85
commit ca838e32b8
15 changed files with 240 additions and 97 deletions

View File

@@ -72,7 +72,7 @@ public record StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, Ex
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(StructType);
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type);
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : LValueExpressionNode(Type);
public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode ValueType, IntTypeNode TargetType) : RValueExpressionNode(Type);

View File

@@ -1,5 +1,3 @@
namespace NubLang.TypeChecking.Node;
public abstract record Node;
public record BlockNode(List<StatementNode> Statements) : Node;
public abstract record Node;

View File

@@ -2,9 +2,13 @@
public abstract record StatementNode : Node;
public abstract record TerminalStatementNode : StatementNode;
public record BlockNode(List<StatementNode> Statements) : StatementNode;
public record StatementExpressionNode(ExpressionNode Expression) : StatementNode;
public record ReturnNode(Optional<ExpressionNode> Value) : StatementNode;
public record ReturnNode(Optional<ExpressionNode> Value) : TerminalStatementNode;
public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value) : StatementNode;
@@ -12,9 +16,11 @@ public record IfNode(ExpressionNode Condition, BlockNode Body, Optional<Variant<
public record VariableDeclarationNode(string Name, Optional<ExpressionNode> Assignment, TypeNode Type) : StatementNode;
public record ContinueNode : StatementNode;
public record ContinueNode : TerminalStatementNode;
public record BreakNode : StatementNode;
public record BreakNode : TerminalStatementNode;
public record DeferNode(StatementNode Statement) : StatementNode;
public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode;

View File

@@ -119,9 +119,10 @@ public class StructTypeField(string name, TypeNode type, bool hasDefaultValue)
public bool HasDefaultValue { get; } = hasDefaultValue;
}
public class StructTypeFunc(string name, FuncTypeNode type)
public class StructTypeFunc(string name, string? hook, FuncTypeNode type)
{
public string Name { get; } = name;
public string? Hook { get; set; } = hook;
public FuncTypeNode Type { get; } = type;
}

View File

@@ -73,7 +73,7 @@ public sealed class TypeChecker
{
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
var funcType = new FuncTypeNode(parameters, ResolveType(function.Signature.ReturnType));
functionTypes.Add(new StructTypeFunc(function.Name, funcType));
functionTypes.Add(new StructTypeFunc(function.Name, function.Hook, funcType));
}
var type = new StructTypeNode(_syntaxTree.Metadata.ModuleName, node.Name, fieldTypes, functionTypes);
@@ -127,10 +127,19 @@ public sealed class TypeChecker
body = CheckBlock(node.Body, scope);
// Insert implicit return for void functions
if (signature.ReturnType is VoidTypeNode && body.Statements.LastOrDefault() is not ReturnNode)
if (!AlwaysReturns(body))
{
body.Statements.Add(new ReturnNode(Optional<ExpressionNode>.Empty()));
if (signature.ReturnType is VoidTypeNode)
{
body.Statements.Add(new ReturnNode(Optional<ExpressionNode>.Empty()));
}
else
{
Diagnostics.Add(Diagnostic
.Error("Not all code paths return a value")
.At(node.Body.Tokens.LastOrDefault())
.Build());
}
}
_funcReturnTypes.Pop();
@@ -150,6 +159,7 @@ public sealed class TypeChecker
ReturnSyntax statement => CheckReturn(statement),
StatementExpressionSyntax statement => CheckStatementExpression(statement),
VariableDeclarationSyntax statement => CheckVariableDeclaration(statement),
DeferSyntax statement => CheckDefer(statement),
WhileSyntax statement => CheckWhile(statement),
ForSyntax statement => CheckFor(statement),
_ => throw new ArgumentOutOfRangeException(nameof(node))
@@ -224,6 +234,11 @@ public sealed class TypeChecker
return new VariableDeclarationNode(statement.Name, Optional.OfNullable(assignmentNode), type);
}
private DeferNode CheckDefer(DeferSyntax statement)
{
return new DeferNode(CheckStatement(statement.Statement));
}
private WhileNode CheckWhile(WhileSyntax statement)
{
var condition = CheckExpression(statement.Condition, new BoolTypeNode());
@@ -734,8 +749,8 @@ public sealed class TypeChecker
if (missingFields.Length != 0)
{
throw new TypeCheckerException(Diagnostic
.Error($"Fields {string.Join(", ", missingFields)} are not initialized")
Diagnostics.Add(Diagnostic
.Warning($"Fields {string.Join(", ", missingFields)} are not initialized")
.At(expression)
.Build());
}
@@ -759,7 +774,7 @@ public sealed class TypeChecker
if (reachable)
{
statements.Add(checkedStatement);
if (checkedStatement is ReturnNode or BreakNode or ContinueNode)
if (checkedStatement is TerminalStatementNode)
{
reachable = false;
}
@@ -779,6 +794,17 @@ public sealed class TypeChecker
return new BlockNode(statements);
}
private bool AlwaysReturns(StatementNode statement)
{
return statement switch
{
ReturnNode => true,
BlockNode block => block.Statements.Count != 0 && AlwaysReturns(block.Statements.Last()),
IfNode ifNode => AlwaysReturns(ifNode.Body) && ifNode.Else.TryGetValue(out var elseStatement) ? elseStatement.Match(AlwaysReturns, AlwaysReturns) : true,
_ => false
};
}
private TypeNode ResolveType(TypeSyntax type)
{
return type switch
@@ -838,7 +864,7 @@ public sealed class TypeChecker
{
var parameters = function.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new FuncTypeNode(parameters, ResolveType(function.ReturnType));
result.Functions.Add(new StructTypeFunc(function.Name, type));
result.Functions.Add(new StructTypeFunc(function.Name, function.Hook, type));
}
ReferencedStructTypes.Add(result);